排序类别 | 排序方式 | 时间复杂度(最好) | 时间复杂度(平均) | 时间复杂度(最差) | 空间复杂度 | 稳定性 | 复杂性 |
---|---|---|---|---|---|---|---|
交换排序 | 冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 | 简单 |
交换排序 | 快速排序 | O(nlogn) | O(nlog2n) | O(n^2) | O(log2n)~O(n) | 不稳定 | 复杂 |
插入排序 | 直接插入排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 | 简单 |
插入排序 | 希尔排序 | O(nlog2n) | O(n^1.3) | O(n^2) | O(1) | 不稳定 | 复杂 |
选择排序 | 简单选择排序 | O(n) | O(n^2) | O(n^2) | O(1) | 不稳定 | 简单 |
选择排序 | 堆排序 | O(nlogn) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 | 复杂 |
归并排序 | 归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 | 复杂 |
交换排序:
- 冒泡排序:两两比较,发现后面的元素小,就交换位置,循环比较 n^2 次
- 快速排序:从一个数组中随机找一个基准值,其他元素与基准值比较,比它小的放一边,比它大的放一边,与它相等放哪边都行,再对两边执行上述操作,递归执行。
插入排序:
- 直接插入排序:从排序的第二个位置算起,与第一个元素比较,若第二个元素比第一个元素小,则把第二个元素赋值为第一个元素值,第一个元素值等于当时的临时变量值(也就是当时的第二个元素值)。将该数值插入到有序集合里,从后往前比较,小就依次往前放,直到大了为止。
外部循环就好比起扑克牌,内部循环就是你从后往前挨个比较的过程,最终放在有序的位置,完成后再次起下一张牌。
基本有序的时候,效率是非常的高 - 希尔排序:插入排序的改进版本,非稳定的算法,对数组进行以某个步长进行分组后对列进行插入排序(将数组列在一个表中并对列排序),重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。最好步长序列(1, 5, 19, 41, 109,…)。步长是随机设定的,目前也没有任何一种方式可以确定使用什么样的步长可以减少排序的时间复杂度。
选择排序:
- 选择排序:第一轮循环,第一个元素和后面的所有元素挨个比较,看哪个数最小就记录下这个数的位置i,第一轮完毕后交换第一个元素和这个位置的元素,紧接着往后循环
- 堆排序(最大堆和最小堆):堆的结构是FIFO,从后面添加元素,从第一个删除元素。简单选择排序的一种改进。
对于数组排序,先堆化数组,第一个元素为最小或最大元素,取出第一个元素拿出来,将第一个元素与叶子的最底层元素交换位置,将该元素除去剩余的元素再做最小堆处理,再交换,再移动,依次类推,直到成为最后一个元素。
其基本思想为(大顶堆):- 将初始待排序关键字序列(R1,R2…Rn)构建成大顶堆,此堆为初始的无须区;
- 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,…Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n]; 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,…Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,…Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2…Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,…Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2…Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
归并排序:
- 递归法:将数组折半分解,直至分组为两个元素,两个元素比较后排序,再归并相邻的有序分组,直到成为一个分组
- 迭代法:直接从前往后两两归并处理,少了拆分递归的步骤,使用归并排序最好使用非递归方法
比较
冒泡和选择排序比较:
区别在于:冒泡算法,每次比较如果发现较小的元素在后面,就交换两个相邻的元素。而选择排序算法的改进在于:先并不急于调换位置,先从A[1]开始逐个检查,看哪个数最小就记下该数所在的位置P,等一躺扫描完毕,再把A[P]和A[1]对调,这时A[1]到A[10]中最小的数据就换到了最前面的位置。
所以,选择排序每扫描一遍数组,只需要一次真正的交换,而冒泡可能需要很多次。比较的次数是一样的。
已知的最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,…),该序列的项来自9×4i−9×2i+1
和2i+2×(2i+2−3)+1
这两个算式[1]。这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序要快,甚至在小数组中比快速排序和堆排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。
快排、堆排
http://users.aims.ac.za/~mackay/sorting/sorting.html
http://mindhacks.cn/2008/06/13/why-is-quicksort-so-quick/