各类排序详解

news2024/12/23 14:11:10

前言

本篇博客将为大家介绍各类排序算法,大家知道,在我们生活中,排序其实是一件很重要的事,我们在网上购物,需要根据不同的需求进行排序,异或是我们在高考完报志愿时,需要看看院校的排名,等等这些都离不开排序;今天我们就来看计算机语言中几类常见的排序算法,如果你对本文感兴趣,欢迎留言交流,下面进入正文部分。

Comparison Sorting Visualization

大家可以通过这个网址来查看各种排序的动图,以便于大家理解。

1.直接插入排序

这个顾名思义,就是将数据取出来比较,然后再插入合适的位置以达到有序的效果;这个就类似于我们玩的扑克牌,当我们摸到拍时,我们需要按照扑克牌的规则对其进行有效的排序,这里其实就是运用了插入排序的思想。

上面介绍了什么是插入排序,下面大家来看看具体代码。

void InsertSort(int* a, int n)
{
	int i = 0;
	for (i = 0; i < n - 1; i++)//这里循环的结束条件需要注意,我们最后一组是a[n-1]=a[n-2]
	{
		int end = i;//假设[0,end]有序,现在将end+1位置的值插入到[0,end],保持有序
		int tmp = a[end + 1];//这里需要先保存end+1位置的值,否则挪动的时候就会覆盖掉后面的数据
		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

直接插入排序的特性总结:

1. 元素集合越接近有序,直接插入排序算法的时间效率越高

2. 时间复杂度:O(N^2)(最坏情况),O(N)(最好情况)

3. 空间复杂度:O(1),它是一种稳定的排序算法

4. 稳定性:稳定

插入排序比起我们之前学过的冒泡排序效率是要高不少的,在实践中我们会用到插入排序,所以大家需要掌握插入排序的写法。

2. 希尔排序

希尔排序是一种比较复杂的排序方法,但是它的效率是比较高的,可以说它是选择排序的一种优化,所以我们必须先理解好插入排序;

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先进行预排序,然后再进行插入排序。

预排序阶段,我们会先定义一个gap,表示一次跳过的间隔,这里其实大家可以根据插入排序去理解gap,当gap等于1时,其实就变成了插入排序。

这里大家需要明确:

gap越大,大数可以越快跳到前面,小数可以越快跳到后面,但是结果越不接近有序;

gap越小,则反之。所以我们需要让gap成为一个变量。

#include<stdio.h>
void ShellSort(int* a,int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		//这里+1是为了让gap最终等于1
		//当gap>1时,执行的是预排序
		//当gap==1时,执行的就是插入排序
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

这里大家注意与插入排序进行对比,代码的逻辑和插入排序是类似的;这里还有一点需要大家注意,就是希尔排序的时间复杂度:O(n^1.3),这个结果大家记忆即可。

3. 选择排序

这个排序属于比较简单的一种排序,基本思想就是找出最大的放后面,找出最小的放前面,然后重复上述过程即可,从这里大家其实就可以感受到这个算法的效率是比较低的,在实践中我们一般是不用它来进行排序的。

void SelectSort(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		if (maxi == mini)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
		begin++;
		end--;
	}
}

直接选择排序的特性总结:

1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

4.快速排序

说到快速排序,这里有三种方法:hoare、挖坑法,前后指针法;我主要为大家介绍前后指针的方法,因为这个方法相对于其他两个好理解一些。

前后指针,顾名思义有两个指针,具体怎么工作呢:刚cur位置的值小于key时,那么prev++,然后将prev位置的值和cur位置的值互换,然后cur指针继续往后走;当cur位置的值大于key时,cur直接往后走;一直到cur越界为止。本质上实现key左边都是比key小的,key右边都是比key大的。

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

int PartSort(int* a, int left, int right)
{
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[keyi], &a[prev]);
	return prev;
}
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
		int keyi = PartSort(a, left, right);
		QuickSort(a, left, keyi - 1);
		QuickSort(a, keyi + 1, right);
}

这里大家看快排的代码,这里运用了递归的思想,在单趟排序中我们得到的就是key的位置,然后在不同的区间进行快排;这里运用递归,很快可以实现快排,但是递归还是存在一定的缺陷,当深度过深时,递归可能会引发栈溢出的问题,所以我们能不能不用递归来实现快排呢?答案当然是可以的。

如果我们想写非递归的快排,那么我们就需要用到栈这个数据结构,本质上是将存在栈帧中的区间放在了栈这个数据结构中,来模拟实现递归的过程;

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
int PartSort2(int* a, int left, int right)
{
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] > a[keyi] && ++prev != cur)
			Swap(&a[prev], &a[cur]);

		cur++;
	}

	Swap(&a[prev], &a[keyi]);
	return prev;
}
void QuickSortNonR(int* a, int left, int right)
{
	ST st;
	STInit(&st);
	//入两个整数,先入右再入左,形成一个区间
	STPush(&st, right);
	STPush(&st, left);
	while (!STEmpty(&st))
	{
		int begin = STTop(&st);//这里出栈就是先出左再出右
		STPop(&st);
		int end = STTop(&st);
		STPop(&st);
		int keyi = PartSort2(a, begin, end);
		if (keyi + 1 < end)
		{
			STPush(&st, end);
			STPush(&st, keyi+1);
		}
		if (begin < keyi - 1)
		{
			STPush(&st, keyi-1);
			STPush(&st, begin);
		}
	}
	STDestroy(&st);
}

这里大家来看非递归的代码,循环每走一次,就取出栈顶区间,然后还是先入右再入左,如此循环下去,就模拟了递归的过程。 

快速排序的特性总结:

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定

5. 堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。

需要注意的是排升序要建大堆,排降序建小堆。

堆排序之所以叫做堆排是因为需要结合堆中的向上调整和向下调整两个算法,具体大家可以看下面代码或者去二叉树那篇文章中查看。

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustUp(int* a, int child)
{
	int parent = (child - 1) / 2;
	while (child >= 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(int* a, int n, int parent)
{
	//这里先假设左孩子小
	int child = parent * 2 + 1;
	while (child < n)//child>=n时,说明已经调整到叶节点了
	{
		//找出小的那个孩子
		if (a[child + 1] > a[child] && child + 1 < n)
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int* a, int n)
{
	int i = 0;
	for (i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

这里我举的例子是建大堆排升序,升降序可以在向下调整和向上调整中进行切换。

堆排的工作原理在于我们要先根据需要建堆,这里就用到向上调整的算法帮助我们建成大堆或小堆;建好堆后,我们需要将首尾位置的数据进行交换,然后让根部位置的数据向下调整,这里拿建大堆排升序来说,我们第一次交换将最大的数放到了最后,然后第二次将次大的数放到倒数第二个位置,以此类推,到最后我们就可以得到一组升序的数据;排降序是同理。 

上面所介绍的是堆排的第一种写法,这种写法是比较容易理解的;但是,我们还有另一种写法,可以在其基础上再提高效率——向下调整建堆。这里大家需要明确一个问题向下调整算法有一个前提:左右子树必须是一个堆,才能调整。所以我们必须保证左右子树都是堆才可以,然而这样显然不太现实,于是我们就采取一种倒着建堆的方式,我们从倒数第一个非叶子节点开始调,一直到根节点,这样也能实现同样的建堆效果。

这里大家还需要注意一点:无论哪种写法,时间复杂度都为:O(NlogN)。但是实际上还是第二种方法能快一些,它们时间复杂度一样,只是说它们属于同一个量级,但是具体详细地来看,还是第二种快,建议大家堆排就写下面这种。

void AdjustDown(int* a, int n, int parent)
{
	//这里先假设左孩子小
	int child = parent * 2 + 1;
	while (child < n)//child>=n时,说明已经调整到叶节点了
	{
		//找出小的那个孩子
		if (a[child + 1] < a[child] && child + 1 < n)
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int* a, int n)
{
	int i = 0;
	for (i = (n-2)/2; i >=0; i--)
	{
		AdjustDown(a, n, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

堆排序的特性总结:

1. 堆排序使用堆来选数,效率就高了很多。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

堆排序是一种效率很高的排序方法,尤其是在数据比较多的情况下,它的运行效率和快排是一个档次的,所以这个排序是具有实际意义的。

6. 归并排序

大家可以直接来看这张图,展现了归并排序的核心思想,我们要采用分治法,保证两边区间都有序后进行归并;

void _MergeSort(int* a, int* tmp, int begin, int end)
{
	if (begin == end)
		return;
	int mid = (begin + end) / 2;
	//递归使左右区间都有序
	_MergeSort(a, tmp, begin, mid);
	_MergeSort(a, tmp, mid+1, end);
	//进行归并
	int begin1 = begin, end1 = mid;
	int begin2 = mid+1, end2 = end;
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, tmp, 0, n - 1);
	free(tmp);
	tmp = NULL;
}

 上面就是归并排序的代码,其实大家可以结合二叉树中的后序遍历来进行理解,这要提醒一下大家,在我们分割区间的时候,要按照上面的方式进行分割,不能分割成[begin,mid-1]和[mid,end],这样会导致程序陷入死循环。

上面我们学习快排的时候,介绍了两种方法,一种是运用递归,一种是运用非递归;那么在这里亦有异曲同工之妙,归并排序也是可以用非递归来实现的。

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	//gap为每组归并数据的个数
	int gap = 1;
	int i = 0;
	while (gap < n)
	{
		for (i = 0; i < n; i += 2 * gap)
		{
			//进行归并
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			if (begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			int j = i;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(int));
		}
		gap *= 2;
	}
	free(tmp);
	tmp = NULL;
}

这里大家来看一下非递归的归并排序,核心思想就是一组一组归并,这里大家要注意我们需要归并一段拷贝一段,区别于上面递归版的归并。

归并排序的特性总结:

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(N)

4. 稳定性:稳定

这里大家可以发现,归并排序也是一种效率很高的排序方法,它的效率和堆排快排是一个档次的,所以具有一定实践意义。

7. 冒泡排序

关于冒泡排序,这里就不赘述了,再前面C语言的文章介绍循环的文章中有,大家有需要的可以自行去我的主页查看。为什么里不详细介绍冒泡呢?原因有二:

其一,冒泡排序比较简单,属于交换排序的一种,如果是初学者可以学习一下冒泡排序,感受一下循环的嵌套。

其二,冒泡排序确实是上不了台面,因为它太慢了,和其他几个不是一个量级的,所以没啥实际意义,只有一定的教学意义。

8. 计数排序

void CountSort(int* a, int n)
{
	int min = a[0];
	int max = a[0];
	int i = 0;
	for (i = 0; i < n; i++)
	{
		if (a[i] < min)
		{
			min = a[i];
		}
		if (a[i] > max)
		{
			max = a[i];
		}
	}
	int range = max - min + 1;
	int* count = (int*)calloc(range, sizeof(int));
	if (count == NULL)
	{
		perror("calloc fail");
		exit(1);
	}
	//统计次数
	for (i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}
	//排序
	int j = 0;
	for (i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[j++] = i + min;
		}
	}
	free(count);
	count = NULL;
}

这里需要为大家强调几点,计数排序只适用于整数,适合范围集中的数据;但是计数排序在特定情况下的效率是很高的,甚至比堆排还要快,所以具有实践意义,我们可以在日常中使用它来进行排序。

 9. 各类排序算法分析

这里主要就是来总结一下各类排序的时间复杂度、空间复杂度、稳定性等因素;首先大家需要明确一下稳定性的一个概念:相同的值相对位置不变。满足这个要求才可以算得上稳定。

10.总结

本篇博客为大家介绍了各种排序算法,其中有一些算法的实践意义不大,有些是可以在实践中进行运用的,大家需要理解每一种排序的思路,并且掌握对应的代码,了解每种排序的特点;排序这块儿内容还是比较重要的,后面我们在面试中,排序是一个常考的点,所以大家需要重点掌握,最后,希望本篇博客可以为大家带来帮助,感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【动手学深度学习】6.2 图像卷积(个人向笔记)

1. 互相关运算 严格来说&#xff0c;卷积层是一个错误的叫法&#xff0c;因为它本质上是互相关运算而不是卷积运算。我们暂时忽略通道看看二维图像数据和隐藏表示。那么输出大小可以表示为 我们自己实现一个二维互相关运算 2. 卷积层 卷积层中有两个参数&#xff1a;卷积核权…

Medieval Kingdom UI 中世纪王国AAA级UI游戏界面

这款中世纪王国风格的大型素材包包含大量绘图、图标、用户界面(UI)元素、完整的世界地图和文明图标。它将助您打造一款游戏,或为您的3D游戏增添亮点。您还可以为对话制作国王的动画,为4K游戏创建独特的面板和窗口。提供两种独特皮肤:经典(冷色调)和白金(暖色调)。 素…

国家基本药物目录数据库查询3种方法(2018、2012、2009年版)

国家基本药物目录是一份由国家卫生健康委员会等相关部门制定的药品清单&#xff0c;旨在满足国家公共卫生需求&#xff0c;保障基本医疗服务。该目录包括了多种药品&#xff0c;覆盖了不同的疾病治疗领域&#xff0c;如抗生素、心血管药物、神经系统药物、抗肿瘤药物、维生素和…

STM32 -- USB CDC 虚拟串口通信

本篇操作: 通过CubeMX Keil&#xff0c;配置STM32作为USB设备端&#xff0c;与电脑上位机进行通信&#xff08;CDC&#xff09;&#xff1b;通用带USB功能的 STM32 芯片 &#xff08;如F1、F4等&#xff0c;系统时钟配置不同&#xff0c;代码通用&#xff09;。 目录 一、 S…

[论文精读]Active and Semi-Supervised Graph Neural Networks for Graph Classification

论文网址&#xff1a;Active and Semi-Supervised Graph Neural Networks for Graph Classification | IEEE Journals & Magazine | IEEE Xplore英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若…

大数据-168 Elasticsearch 单机云服务器部署运行 详细流程

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

PyQt: QMessageBox Duplication

在使用 PyQt 的 QMessageBox 时&#xff0c;如果你遇到 消息框重复显示 或 QMessageBox 重复实例化 的问题&#xff0c;通常是因为消息框没有正确管理或关闭&#xff0c;或者消息框的创建和显示逻辑中存在重复调用。以下是一些常见原因和解决方案。 1、问题背景 在 PyQt 中使用…

无心剑七绝《泊院雕楼》

七绝泊院雕楼 清歌咏尽桂花香 泊院雕楼醉夕阳 逸兴无端飞万里 幽情宛转忆潇湘 2024年10月13日 平水韵七阳平韵 这首七绝《泊院雕楼》以清新脱俗的语言&#xff0c;描绘了一幅宁静致远的画面。 首句“清歌咏尽桂花香”&#xff0c;以“清歌”起兴&#xff0c;形象地描绘了桂花香…

C++——类和对象(三)

一.赋值运算符 1.运算符重载 (1) 运算符重载是具有特殊名字的函数&#xff0c;他的名字是由operator和后面要定义的运算符共同构成。和其他函数一样&#xff0c;它也具有其返回类型和参数列表以及函数体。 (2) 重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。…

React.createRef(),React.forwardRef(),forwardRef()结合next.js的link进行路由跳转

码云https://gitee.com/skyvilm/react-next.js 1.React.createRef() 作用&#xff1a;获取dom元素 使用 import React,{Component} from react export default class Index extends Componen{ constructor(props){ super(props) this.myrefReact.createRef(); //创建节点 } c…

如何批量从sql语句中提取表名

简介 使用的卢易表 的提取表名功能&#xff0c;可以从sql语句中批量提取表名。采用纯文本sql语法分析&#xff0c;无需连接数据库&#xff0c;支持从含非sql语句的文件文件中提取&#xff0c;支持各类数据库sql语法。 特点 快&#xff1a;从成百个文件中提取上千个表名只需1…

集成方案 | 借助 Microsoft Copilot for Sales 与 Docusign,加速销售流程!

加速协议信息提取&#xff0c;随时优化邮件内容~ 在当今信息爆炸的时代&#xff0c;销售人员掌握着丰富的数据资源。他们能够通过 CRM 平台、电子邮件、合同库以及其他多种记录系统&#xff0c;随时检索特定个人或组织的关键信息。这些数据对于销售沟通至关重要。然而&#x…

【端到端】CVPR 2023最佳论文:UniAD解读

作者&#xff1a;知乎一根呆毛授权发布 传统的端到端网络是用多个小model串起来&#xff0c;但这会有误差累积的问题&#xff0c;因此我们提出了UniAD&#xff0c;一个综合框架&#xff0c;把所有任务整合到一个网络。整一个网络都是为planner而进行设计的。 Introduction a传…

SQL性能优化指南:如何优化MySQL多表join场景

目录 多表join问题SQL 这里解释下 Using join buffer (Block Nested Loop)&#xff1a; 对性能产生的影响&#xff1a; 三种join算法介绍 join操作主要使用以下几种算法&#xff1a; &#xff08;1&#xff09;Nested Loop Join &#xff08;2&#xff09;Block Nested …

生信服务器配置:优化生物信息学数据处理的最佳实践

介绍 在生物信息学研究中&#xff0c;处理和分析大规模数据集&#xff08;如基因组、转录组和蛋白质组数据&#xff09;需要强大的计算资源和精确的服务器配置。生信服务器配置的优化可以显著提高数据处理的效率和结果的准确性。本文将探讨生信服务器配置的关键要素&#xff0…

【LeetCode热题100】分治-快排

本篇博客记录分治快排的4道题目&#xff1a;颜色分类、排序数组、数组中的第K个最大元素、数组中最小的N个元素&#xff08;库存管理&#xff09;。 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int left -1,right n;for(int…

【实战项目】——Boost搜索引擎(五万字)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、项目的相关背景 1.1、什么是Boost库&#xff1f; 1.2、什么是搜索引擎&#xff1f; 1.3、为什么要做Boost库搜索引擎&#xff1f; 二、搜索引擎的宏观原…

VirtualBOX虚拟机提高速度,鼠标卡顿解决——未来之窗数据恢复

一、刚安装完操作系统&#xff0c;鼠标操作不灵敏 需要安装系统增强 二、系统增强作用 1.鼠标丝滑 2.文件共享 3.可以共享剪贴板 三、安装步骤-设备-安装增强 四、安装步骤-设备-选择光驱 五、安装增强软件然后重启 六、阿雪技术观 拥抱开源与共享&#xff0c;见证科技进…

【算法】动态规划:从斐波那契数列到背包问题

【算法】动态规划&#xff1a;从斐波那契数列到背包问题 文章目录 【算法】动态规划&#xff1a;从斐波那契数列到背包问题1.斐波那契数列2.爬楼梯3.零钱转换Python代码 4.零钱兑换 II5.组合数dp和排列数dp6.为什么动态规划的核心思想计算组合数的正确方法代码实现 为什么先遍历…

【C++打怪之路Lv8】-- string类

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;重生之我在学Linux&#xff0c;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持…