0%

排序算法概况

今天将多年前整理的一些排序算法捋一捋。先说个大概。

排序算法通常按照以下标准分类:

1. 依据待排序数列的大小 计算时间复杂度(最差、平均及最好性能)。

  • 一般而言,好的性能是 ,坏的性能是
  • 对于一次排序,理想的性能是 ;然而在平均上总是需要

2. 存储器使用量(以及其他计算机资源的使用)

3. 稳定性:指的是某个排序算法会让原本有相同键值的记录维持相对次序。

  • 如果一个排序算法是稳定的,当有两个相同键值的记录 R 和 S,且在原本数列中 R 出现在 S 之前,那么在排序过的数列之中,R 也将会在 S 之前。


稳定排序算法

不稳定排序算法

怎么记忆哪些是稳定算法?

  • 时间复杂度复杂一些的(高级,包括快排、shell 排序、堆排序 —— 归并排序除外)都不稳定(选择排序也不稳定);
  • 时间复杂度简单一些的(低级,包括冒泡、插入、计数、基数)都稳定(归并排序也是稳定的);
  • 复杂算法中,归并排序是稳定排序;简单算法中,选择排序不稳定;
  • 8 种稳定,4 种不稳定。

比较 v.s. 不比较

基于比较的排序(Comparison Sort):通过对序列中的数据进行比较,确定数据的先后顺序。

包括:

比较排序有着局限性:不能突破 的复杂性下限。

  • 简单证明: 个数有 个可能的全排列,即基于比较的排序算法的判定树有 个叶节点,比较次数最少为 (斯特林公式)

相对应的,非比较排序有:

非比较排序的局限性是:对排序元素之间差值的大小有限制。

算法性能

总结了个表格(n 为数据量大小):

类别 排序方法 数据对象 稳定性 时间复杂度 空间复杂度
平均情况 最好情况 最坏情况
插入排序 直接插入排序 数组、链表 ☑️ O(n2) O(n) O(n2) O(1)
shell 排序 数组 ✖️ O(nlogn) O(n) O(nlogn) O(1)
选择排序 直接选择排序 数组 ✖️ O(n2) O(n2) O(n2) O(1)
链表 ☑️
堆排序 数组 ✖️ O(nlogn) O(nlogn) O(nlogn) O(1)
交换排序 冒泡排序 数组 ☑️ O(n2) O(n) O(n2) O(1)
快速排序 数组 ✖️ O(nlogn) O(nlogn) O(n2) O(logn)
归并排序 数组、链表 ☑️ O(nlogn) O(nlogn) O(nlogn) O(n)
桶排序 数组、链表 ☑️ O(n+k) O(n+k) O(n2) O(n+k)
基数排序 数组 ☑️ O(nk) O(nk) O(nk) O(n+k)
计数排序 数组、链表 ☑️ O(n+k) O(n+k) O(n+k) O(n+k)

注:对于非比较排序来说,k 为“桶”的个数。

再上个教材的图: