# 排序总结&避坑指南

时间复杂 额外空间复杂 稳定性
选择排序 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(M)
基数排序 O(N) O(N)

# 排序算法的稳定性

  • 稳定性,是指在排序后,同样大小的样本之间的相对顺序不会发生变化。
  • 对于基础类型而言,稳定性似乎毫无意义。
  • 但是,对于那些非基础类型,稳定性却蕴含着深刻的含义和价值。
  • 有一些排序算法被设计成可以保持相对顺序的稳定状态,然而,也有一些排序算法,无论如何都无法达到稳定。🎭

# 场景展示

在排序的大舞台上,稳定性是一种珍贵的品质,如同排序算法的黄金标志。让我们深入探索一下为什么在各种场景中都需要排序的稳定性。

  1. 购物之旅:价格与好评度的完美组合

    想象一下购物时,你希望按照价格排序,但同时也希望在同一价格范围内按照好评度排序。如果排序不稳定,先按价格排序可能会打乱原本按好评度有序的商品顺序。排序的稳定性就像是购物清单的魔法符咒,确保了你的排序需求不会互相干扰。

  2. 班级秩序:年龄与班级的和谐共舞

    在学生大家庭中,我们可能需要按照年龄排序,然后再按照班级排序。如果排序不稳定,可能导致同年龄的学生在排序后位置发生变化,打破了原有的年龄序列。排序的稳定性就像是班级里的年龄秩序守护者,确保了排序的和谐进行。

为什么需要排序的稳定性?

  1. 维护相对顺序关系:

    • 稳定性确保了相等元素在排序后仍然保持原有的相对顺序。这对于多级排序场景非常关键,比如购物时的价格与好评度。
  2. 不破坏先前排序:

    • 排序稳定性意味着如果两个元素相等,排序的结果不会改变它们之间的相对位置。这对于多次排序操作非常重要,比如先按年龄排序再按班级排序。
  3. 提高排序的可控性:

    • 稳定性让我们能够更加精确地控制排序的结果,确保在不同排序阶段的需求都能得到满足。

# 总结

  1. 不基于比较的排序,对样本数据有严格要求,不易改写
  2. 基于比较的排序,只要规定好两个样本怎么比大小就可以直接复用
  3. 基于比较的排序, 时间复杂度的极限是O(N*logN)
  4. 时间复杂度O(N*logN) 、额外空间复杂度低于O(N) 、且稳定的基于比较的排序是不存在的。
  5. 为了绝对的速度选快排、为了省空间选堆排、为了稳定性选归并

# 常见的坑

  1. 归并排序的额外空间复杂度可以变成O(1),“归并排序内部缓存法”,是将变得不再稳定。
  2. “原地归并排序”是垃圾贴,会让时间复杂度变成O(N^2)
  3. 快速排序稳定性改进,“01 stable sort", 但是会对样本数据要求更多。

# 工程上对排序的改进

  1. 稳定性的考虑
  2. 充分利用 O(N*logN) 和 O(n^2) 排序各自的优势
上次更新: 1/19/2024,