Sorting
总结排序算法,不局限于本课程所述的部分
综述
问题
假设要将一个大小为 的从小到大排序。
思路
1. 每次将一个元素移动到最终位置
一些排序算法,如选择排序 (selection sort),冒泡排序 (bubble sort) 以及堆排序 (heap sort),每次将一个元素移动到最终位置,这样就能将大小为 的问题转化成大小为 的问题。
2. 每次将每个元素放到更接近最终位置的地方
一些排序算法,如插入排序 (insertion sort),快速排序 (quick sort),计数排序 (counting sort) 以及基数排序 (radix sort),每次将每个元素放到更接近最终位置的地方,使得整体序列的逆序数量逐渐变少,并最终达到排序目的。
3. 分治
如归并排序 (merge sort)
复杂度和运行时
排序至少要遍历一遍待排序列,因此排序算法的复杂度为
影响复杂度的因素包括:
算法本身的流程复杂程度及启动开销:简单的算法虽然复杂度常为 ,但它的其它开销(常数项)可能很小,因此面对长度较小(如 < 10)的序列常常有更快的性能。因此实际运用中,常常会通过判断序列大小来选择所使用的排序算法
多余的空间,如变量及递归的栈空间
缓存:算法运行过程中的大部分比较操作如果都是发生在相邻元素之间,就容易利用数据的空间分布特点,获得更高的缓存命中率以及数据预取
各种类型的输入考量:乱序、已经排好序、倒着排好序、接近排好序等
基于比较的排序算法对待排序列没有任何假设,理想情况下,在任何输入面前都能够做到 的算法复杂度,如堆排序、归并排序等。
如果我们可以对数据做一些额外的假设,就可能获得比 更好的算法复杂度,如在计数排序中,我们假设数据分布在一定范围内。
排序算法集锦
冒泡排序(Bubble Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
Best |
|
|
Worst |
|
|
Average |
|
|
思路
从左往右冒泡,每次比较左右两个元素,如果前者大于后者,则交换位置,一共循环 次,第 i 次循环结束时,第 i 大的元素都会移动到正确的位置上。
选择排序(Selection Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
All |
|
|
思路
选择排序是所有排序中最直观的排序,从左开始,每次从剩余元素中选择最大(小)的元素,放到剩余序列的最右(左)边。
插入排序(Insertion Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
Best |
|
|
Worst |
|
|
Average |
|
|
思路
插入排序与打扑克时整理牌的方法类似,从左向右开始,第 i 轮结束保证前 i 个元素已经排好序。
快速排序(Quick Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
Best |
|
|
Worst |
|
|
Average |
|
|
思路
有点像二分,每次选取一个 pivot,将所有小于 pivot 的数和所有大于 pivot 的数,分别作为两个子序列,递归地排序。其中 pivot 的选择决定了最终排序的复杂度。
快速排序快的原因在于:
pivot 选择得好时,能够获得 的时间复杂度
它利用了 spatial locality,总是比较相邻的元素,因此很好地利用 cache
堆排序(Heap Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
All |
|
|
使用堆(具体参考 Priority Queue Interface & Implementation 一节),先对原序列建堆(原地建堆可以获得 的空间复杂度),后每次从堆中 pop 出最大值,放到序列末尾即可。
归并排序(Merge Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
All |
|
|
思路
每次将序列二等分,各部分排好序后,再合并。
计数排序(Counting Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
All |
|
|
其中 n 表述序列大小,k 表示元素的范围大小
思路
统计元素所处范围内中每个元素的数量,然后从小到大遍历生成新序列即可
基数排序(Radix Sort)
复杂度小结
Case | Time Complexity | Space Complexity |
All |
|
|
其中,d 表示最大数的位数,k 表示元素基数大小(如二进制,k = 2;十进制,k = 10)
思路
从最小的位数开始,如十进制中的个位,每轮对所有元素的该位数进行一次计数排序。
现实中的排序算法
TimSort
复杂度小结
Case | Time Complexity | Space Complexity |
All |
|
|
思路
当序列较小时,使用插入排序;当序列较大时,先将序列分成多组,每组先使用插入排序,后对不同组递归地使用归并排序中的归并步骤。
外排序算法
TODO
参考 https://github.com/melvilgit/external-Merge-Sort
参考
Last updated