贰.1.1 十大排序算法
先看一张图表总结个中排序算法对比(点击可看大图)。

或看下面这张更经典的

01. 冒泡排序
冒泡排序是一种简单的排序算法,它重复地遍历要排序的数组,比较相邻的两个元素,如果它们的顺序错误就交换它们的位置。这个过程会一直重复,直到没有再需要交换的元素,也就是说该数组已经排序完成。
因为嵌套两个for循环,所以冒泡排序的时间复杂度为 ,空间复杂度为 (只需要一个临时变量来交换元素)。
动画演示

02. 选择排序
假设数组A里面有N个项,选择排序是这样的:数组A第i个项记作 ,第(i+1)~(N-1)项中的最小(最大的情况也是相似的逻辑)值记作 ,然后比较它俩大小,如果 小于 ,交换位置……直到把整个数组处理一遍。代码如下:
可以看出选择排序也是一外一内两个for循环,因此时间复杂度也是 ,空间复杂度为 。但是选择排序与冒泡排序差别地方在于:
选择排序的位置交换是在第二个for循环之外,第一个for循环之内,因此选择排序交换位置最多N次,而冒泡排序最多可能 次。所以大多数情况下,选择排序比冒泡排序效率好一些。
动画演示

03. 插入排序
插入排序我们打扑克时给手中牌排序的思路一样,刚开始左手上一堆乱序的牌,我们把牌往手的右边挪一挪,把手的左边空出一点位置来,然后在右手乱牌中抽一张出来,插入到左边,再抽一张出来,插入到左边……每次插入都插入到左边合适的位置,时刻保持左边的牌是有序的,直到右边的牌抽完,则排序完毕。
代码实现如下:
从代码里我们可以看出,如果找到了合适的位置,就不会再进行比较了,就好比右手里抽出的一张牌本身就比我左手里的牌都小,那么我只需要直接放在左手靠边位置就行了,不用一张一张去移动牌腾出位置插入到中间。
所以说,最好情况的时间复杂度是 ,最坏情况的时间复杂度是 ,然而时间复杂度这个指标看的是最坏的情况,而不是最好的情况,所以插入排序的时间复杂度也是 。空间复杂度为 。
动画演示

04. 堆排序
堆的特性:
必须是完全二叉树;
任一结点的值是其子树所有结点的最大值或最小值。 最大值时,称为"最大堆",也称大顶堆; 最小值时,称为"最小堆",也称小顶堆。
堆排序主要用到最大堆/最小堆的删除操作,也即根节点已经是最大/小的值,排序的话,只需要把根结点拿(删)掉,放入有序的新数组里,然后用下沉算法处理剩余的结点以便组成新的最大堆/最小堆……如此循环。
所谓下沉算法,拿最小堆来举例说(最大堆同理),就是把完全二叉树根结点R和该树第二层左右子结点的值比较,如果大,结点就互换位置("下沉"),以此逐层递归,直到处理完整棵树,此时,根节点值最小。
草稿图可以这么画,然后归纳、设计代码,更方便理解。

堆排序的时间复杂度是 ,空间复杂度为 (原地排序)。
动画演示

05. 归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序的核心思想是:
将数组分成两半
递归地对两半进行归并排序
将两个有序数组合并成一个有序数组
归并排序的时间复杂度是 ,空间复杂度是 。它的优点是稳定排序,时间复杂度稳定,缺点是需要额外的空间。
动画演示

06. 快速排序
快速排序其实是分治法,将待排序数组里的项和基准数对比,比基准数大的放在一边,小的放另一边,然后再对左右两边的子数组重复使用这个思路,直到整个数组排序完毕。
时间复杂度最好的情况是 ,最差的情况是 。算法分析:
当分区选取的基准元素为待排序元素中的最大或最小值时,为最差的情况,时间复杂度和直接插入排序的一样,移动次数达到最大值
Cmax = 1+2+...+(n-1) = n*(n-1)/2 = O(n2)此时时间复杂为 ;当分区选取的基准元素为待排序元素中的"中值",为最好的情况,时间复杂度为 。
快速排序的空间复杂度为 (递归调用栈的深度),最坏情况下为 。
动画演示

07. 希尔排序
希尔排序是插入排序的一种改进版本,也称为缩小增量排序。它通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到最后一趟比较相邻元素。
希尔排序的核心思想是:
设定一个初始间隔gap
按照gap分组,对每组使用插入排序
减小gap,重复步骤2
当gap=1时,就是普通的插入排序
希尔排序的时间复杂度取决于间隔序列的选择,最坏情况下是 ,但在实际应用中通常比 要好。空间复杂度为 。它的优点是对于中等大小的数组表现良好,且代码相对简单。
动画演示

08. 计数排序
计数排序是一种非比较排序算法,它通过统计每个元素出现的次数来进行排序。计数排序适用于已知数据范围的整数排序,特别是当数据范围不大时效率很高。
计数排序的核心思想是:
统计每个元素出现的次数
根据统计结果重构原数组
计数排序的时间复杂度是 ,其中K是数据范围。空间复杂度为 。当数据范围不大时,计数排序的效率很高,但需要额外的空间来存储计数数组。
动画演示

09. 桶排序
桶排序是计数排序的升级版,它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶中,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
桶排序的核心思想是:
将数据分到有限数量的桶中
对每个桶中的数据进行排序
将桶中的数据按顺序合并
桶排序的时间复杂度是 ,其中K是桶的数量。空间复杂度为 。当数据分布均匀时,桶排序的效率很高,但需要额外的空间来存储桶。
动画演示

10. 基数排序
基数排序是一种非比较排序算法,它通过将整数按位数切割成不同的数字,然后按每个位数分别比较来进行排序。基数排序适用于整数排序,特别是当数据范围很大但位数相对较少时。
基数排序的核心思想是:
从最低位开始,按每一位进行排序
使用稳定的排序算法(如计数排序)对每一位进行排序
重复步骤1-2,直到最高位
基数排序的时间复杂度是 ,其中D是最大数的位数,K是基数(通常是10)。空间复杂度为 。基数排序适用于整数排序,特别是当数据范围很大但位数相对较少时效率很高。
动画演示

总结
以上十种排序算法各有特点:
按时间复杂度分类:
冒泡排序、选择排序、插入排序:时间复杂度 ,适合小数据量
希尔排序:改进的插入排序,时间复杂度介于 和 之间
堆排序、归并排序、快速排序:时间复杂度 ,适合大数据量
计数排序、桶排序、基数排序:时间复杂度 ,适合特定数据分布
按空间复杂度分类:
原地排序():冒泡排序、选择排序、插入排序、堆排序、希尔排序
需要额外空间( 或更高):归并排序、快速排序、计数排序、桶排序、基数排序
按稳定性分类:
稳定排序:冒泡排序、插入排序、归并排序、计数排序、桶排序、基数排序
不稳定排序:选择排序、堆排序、快速排序、希尔排序
在实际应用中,需要根据数据规模、数据特征、稳定性要求、内存限制等因素来选择合适的排序算法。
最后更新于
这有帮助吗?