简单的排序-复杂度高
插入排序-稳定
- 思想:序列分为已排序和未排序两部分,未排序的一个个向前插入到已排序的序列中
- 复杂度:$O(n^2)$
- 当n较小的时候,插入排序较为高效
- 优化:不用每次比较都交换
- 再优化:二分查找 比较次数降为$O(nlog^n)$,移动次数不变,最佳情况时间代价降低,但最差和平均不变
冒泡排序-稳定
- 思想:比较相邻的记录,一次次将最小值冒出
- 复杂度:由于比较次数恒定,最大最小平均都是$O(n^2)$
- 优化:有一次冒泡过程中没有发生过交换就可以跳出循环
- 最小时间代价变为$O(n)$
直接选择排序-不稳定
- 思想:序列分为已排序和未排序,将未排序中最小值和未排序序列最前面那个元素互换
- 复杂度:时间$O(n^2)$空间$O(1)$
shell排序(缩小增量排序)-不稳定
- 思想:插入排序在待排序序列较短的时候效率高,整体有序的时候时间代价低,所以将原始序列进行等间隔的小序列分割对它们进行直接插入排序,逐步扩大序列规模(较少相隔数),最后对整个序列进行完整的插入排序
- 具体实现:选定一个间隔增量序列,彼此相距d的记录划为一组,在各组内插入排序
- 复杂度:根据增量序列决定,差不多是$O(n^frac{3}{2})$
分治排序
快速排序-不稳定
- 思想:在待排序列中选择轴值作为划分基准,调换这两个序列中元素的位置使得最后轴值放入正确排序位,左边的元素都比它小,而右边的元素都比它大
- 具体实现:左右指针,两个循环
- 复杂度:最佳性能$O(nlg^n)$最差$O(n^2)$平均:$O(nlog^n)$
归并排序-稳定
- 思想:将序列划分为两个子序列然后递归合并
- 复杂度:$O(nlog^n)$,存储量$O(n)$
堆排序-不稳定
- 使用最大堆每次查出最大的值移到数组末端,重新将剩下n-1个记录建堆,再重复
- 复杂度:建堆$O(n)$,每次提取最大$O(log^n)$,总的:$O(nlog^n)$(最好最差平均都是这个)
分配排序
桶排序-稳定
- 思想:统计每个取值出现的次数来确定某个值出现的位置
- 时间复杂度:$O(m+n)$,空间代价:$O(m+n)$
- 适用于m相对于n很小的情况
基数排序-稳定
- 适用情况:排序码有多个,比如比较大的数的比较
- 分类:高位优先法
- 桶中分桶,每一位桶式排序后,将序列分成若干个桶,按后一位排序码排序时分出更小的桶……(递归分治)
- 分类:低位优先法(常用)
- 由于对低位排序后,桶式排序是稳定的,可以保证当高位相同时,低位按顺序排好。
- 实现:
- 顺序存储
- 待排序数组长度n,基数r,排序码位数d
- 复杂度:$O(d(r+n))$
- 静态链存储
- 避免在分配和收集时都需要移动所有记录,只需连接每个桶即可获得排序后的序列
- 复杂度:$O(d*n)$~差不多$O(nlog^n)$
- 顺序存储
索引排序(地址排序)
- 思想:记录自身规模较大时,用移动地址或索引来替代移动记录,可以基于任何排序方法做
- 实现(两种):记录原数组在排序后在序列中的位置;或记录排序后数组里的元素在排序前在序列中的位置。移动本体的时候找环移动,顺链调整。
排序问题的下限应该在$Ω(n)$到$O(nlog^n)$之间
判定树:判定树的最大深度是排序算法在最差情况下需要的比较次数,最小深度是最佳情况下的比较次数