1、排序算法分类
前面介绍的几种排序算法可以分为两大类:
比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(N*logN),因此也称为非线性时间比较类排序。
非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
2、排序算法复杂度和稳定分析
| 排序算法 | 时间复杂度 | 额外空间复杂度 | 稳定性 |
|---|---|---|---|
| 选择排序 | O(N^2) | O(1) | 不稳定 |
| 冒泡排序 | O(N^2) | O(1) | 稳定 |
| 插入排序 | O(N^2) | O(1) | 稳定 |
| 归并排序 | O(N*logN) | O(N) | 稳定 |
| 随机快排 | O(N*logN) | O(logN) | 不稳定 |
| 堆排序 | O(N*logN) | O(1) | 不稳定 |
| 计数排序 | O(N) | O(N) | 稳定 |
| 基数排序 | O(N) | O(N) | 稳定 |
稳定性
- 稳定:如果 a 原本在 b 前面,而 a = b,排序之后 a 仍然在b的前面。
- 不稳定:如果 a 原本在 b 的前面,而 a = b,排序之后 a 可能会出现在 b 的后面。
3、排序算法的总结
-
不基于比较的排序,对样本数据有严格要求,不易改写
-
基于比较的排序,只要规定好两个样本怎么比大小,就可以直接复用
-
基于比较的排序,时间复杂度的极限是
O(N*logN) -
时间复杂度
O(N*logN)、额外空间复杂度低于O(N)、且稳定的基于比较的排序是不存在的。 -
为了绝对的速度选快排、为了省空间选堆排、为了稳定性选归并
4、常见问题
-
归并排序的额外空间复杂度可以变成
O(1),归并排序 内部缓存法,但是将变得不再稳定。这个是可以实现,但是会变得不稳定,这个地方完全可以用堆排序替代
-
原地归并排序 是垃圾贴,会让时间复杂度变成
O(N^2)这个地方完全可以用插入排序替代
-
快速排序稳定性改进,01 stable sort,但是会对样本数据要求更多。
限制如此的多,这个地方为什么不用桶排序呢?可以实现,但是完全没必要
-
在整型数组中,请把奇数放在数组左边,偶数放在数组右边,要求所有奇数之间原始的相对次序不变,所有偶数之间原始相对次序不变。还需要保证时间复杂度做到
O(N),额外空间复杂度做到O(1)这是一个 0|1 类型的 partition,快排经典的 partition 是做不到稳定性,如果上述问题可以实现,为什么快排不改成稳定性的?
-
工程上对排序的改进
-
稳定性的考虑
-
充分利用
O(N*logN)和O(N^2)排序各自的优势
将多种排序的优势集中到一起的排序,比如 Arrays.sort()
方法会通过反射获取要排序的数组的类型,如果是基本类型的,直接用插入/快排,如果是引用排序的会用归并排序。这里主要是为了不破坏引用类型的排序后的稳定性
-