算法数据结构:排序总结

361 阅读3分钟

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、排序算法的总结

  1. 不基于比较的排序,对样本数据有严格要求,不易改写

  2. 基于比较的排序,只要规定好两个样本怎么比大小,就可以直接复用

  3. 基于比较的排序,时间复杂度的极限是O(N*logN)

  4. 时间复杂度O(N*logN)、额外空间复杂度低于O(N)、且稳定的基于比较的排序是不存在的。

  5. 为了绝对的速度选快排、为了省空间选堆排、为了稳定性选归并

4、常见问题

  1. 归并排序的额外空间复杂度可以变成O(1)归并排序 内部缓存法,但是将变得不再稳定。

    这个是可以实现,但是会变得不稳定,这个地方完全可以用堆排序替代

  2. 原地归并排序 是垃圾贴,会让时间复杂度变成O(N^2)

    这个地方完全可以用插入排序替代

  3. 快速排序稳定性改进,01 stable sort,但是会对样本数据要求更多。

    限制如此的多,这个地方为什么不用桶排序呢?可以实现,但是完全没必要

  4. 在整型数组中,请把奇数放在数组左边,偶数放在数组右边,要求所有奇数之间原始的相对次序不变,所有偶数之间原始相对次序不变。还需要保证时间复杂度做到O(N),额外空间复杂度做到O(1)

    这是一个 0|1 类型的 partition,快排经典的 partition 是做不到稳定性,如果上述问题可以实现,为什么快排不改成稳定性的?

  5. 工程上对排序的改进

    • 稳定性的考虑

    • 充分利用O(N*logN)O(N^2)排序各自的优势

    将多种排序的优势集中到一起的排序,比如 Arrays.sort()

    方法会通过反射获取要排序的数组的类型,如果是基本类型的,直接用插入/快排,如果是引用排序的会用归并排序。这里主要是为了不破坏引用类型的排序后的稳定性