面试的时候八大排序倒背如流,工作几年后发现实际开发里真用得上的就那么两三个。整理一下哪些该深挖、哪些面试背完就得了。
先放结论:实际开发 90% 的场景,直接用语言自带的排序就够了。 Java 的 Arrays.sort()、Python 的 sorted(),底层都是经过高度优化的(Tim Sort / 双轴快排),比你手写的任何排序都快。手写排序的意义在于理解原理和应对面试,不是让你在生产环境替代标准库。
逐个说:
快速排序 — 唯一值得深挖的
实际工程里接触最多的排序底层就是快排。Java Arrays.sort() 对基本类型用双轴快排(Dual-Pivot Quicksort),理解快排的分区逻辑对你看懂标准库源码有帮助。
关键点不是怎么写,是怎么选 pivot。取第一个元素是教科书写法,实际遇到已排序数组直接退化到 O(n²)。三数中值法(左端、右端、中位数的中间值)是基本操作,更稳的是随机选 pivot。
// 核心:分区,不是排序本身
int partition(int[] a, int low, int high) {
int pivot = a[low]; // 实际用三数中值法
while (low < high) {
while (low < high && a[high] >= pivot) high--;
a[low] = a[high];
while (low < high && a[low] <= pivot) low++;
a[high] = a[low];
}
a[low] = pivot;
return low;
}
平均 O(nlogn),最坏 O(n²),不稳定。但实际优化后(随机 pivot + 小数组切插入排序)极难触发最坏情况。
归并排序 — 理解 Tim Sort 的基础
Tim Sort(Python/Java 对象排序用的)就是归并的变种。归并排序本身在面试里考得多,实际手写场景少。
几个容易被问的细节:
- 时间复杂度最好最坏都是 O(nlogn),稳定
- **额外空间是 O(n)**,不是 O(1)——需要临时数组,这点很多人记错
- 适合链表排序(不需要随机访问)、外部排序(数据量大到内存放不下)
堆排序 — 知道原理就行
面试会问 Top-K 问题,本质就是堆。但手写堆排序的场景我工作几年没遇到过。理解大根堆/小根堆的调整逻辑,知道 PriorityQueue 怎么用,够了。
时间复杂度 O(nlogn),不稳定。堆排序的常数比快排大,实际跑起来比快排慢,所以标准库基本不用纯堆排序。
插入排序 — 小数据量王者
这个反而容易被忽略。当数据量小(通常 < 47)时,插入排序比快排快——没有递归开销,常数小。Java 的 Arrays.sort() 在子数组小于阈值时就会切到插入排序(双轴快排里叫 “insertion sort on small arrays”)。
大部分已排序时效率高,最好情况 O(n)。稳定,额外空间 O(1)。
冒泡排序 — 面试背完就得了
唯一的价值是理解”交换排序”的思路。实际开发没有任何场景该用冒泡。加 flag 优化的版本最好情况 O(n),但插入排序同样能做到且常数更小。
别拿冒泡去面试写手撕代码,写快排或归并。
选择排序 — 同上
不稳定,且最好最坏都是 O(n²)。没有任何实际优势,唯一的教学价值是理解”选择”思路。
希尔排序 — 知道是插入排序的改进就行
希尔排序是插入排序的分组改进版,通过增量序列逐步缩减让元素大致有序。时间复杂度取决于增量序列,最好可以到 O(nlogn),最坏 O(n²)。
实际工程基本不用,但面试偶尔会问”希尔排序和插入排序的关系”。
桶排序 / 计数排序 — 特定场景才用
非比较排序,时间复杂度可以到 O(n),但限制大:
- 值域必须是可枚举的整数范围
- 值域 k 和数据量 n 接近时才划算(k >> n 时空间浪费严重)
- **额外空间 O(k)**,不是 O(1)
实际场景:给百万级年龄数据排序(0-150 的值域),计数排序秒杀一切比较排序。但你给字符串排序就别想了。
一张表总结(修正了常见错误):
| 排序 | 平均时间 | 最坏 | 稳定 | 额外空间 | 实际价值 |
|---|---|---|---|---|---|
| 快排 | O(nlogn) | O(n²) | 不稳定 | O(logn) | ★★★ 最高 |
| 归并 | O(nlogn) | O(nlogn) | 稳定 | O(n) | ★★★ Tim Sort 基础 |
| 堆排 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | ★★ Top-K 场景 |
| 插入 | O(n²) | O(n²) | 稳定 | O(1) | ★★★ 小数据量王者 |
| 希尔 | O(nlogn) | O(n²) | 不稳定 | O(1) | ★ 知道原理就行 |
| 冒泡 | O(n²) | O(n²) | 稳定 | O(1) | ✗ 教学用 |
| 选择 | O(n²) | O(n²) | 不稳定 | O(1) | ✗ 教学用 |
| 桶/计数 | O(n+k) | O(n+k) | 稳定 | O(k) | ★★ 特定场景 |
网上很多教程的总结表把归并的额外空间写成 O(1)、桶排序写成 O(1),都是错的。归并需要临时数组 O(n),桶/计数排序需要计数数组 O(k)。
所以面试该重点准备哪些?
快排(必手撕)、归并(必手撕)、堆排(理解 + Top-K)、插入排序(能说出小数据量优势)。其余的知道原理和复杂度就行,别花时间手写。
原文有完整的 Java 代码实现(八种排序全有),在我博客上 tanqingbo.cn/Eight-sorting-algorithms ,需要的自查。