排序算法是计算机科学中最基础、最重要的一类算法问题。几乎所有涉及数据处理、检索、分析与存储的系统,最终都绕不开“排序”。
本文系统梳理 十大经典排序算法,从算法思想、时间复杂度、空间复杂度、稳定性与工程适用场景五个维度进行全面解析,帮助你真正理解“什么时候该用哪一种排序”。
一、排序算法的核心评价指标
在进入具体算法前,先明确几个关键概念:
1. 时间复杂度
- O(n²):低效,仅适合小规模数据
- O(n log n):高效主流复杂度
- O(n):线性排序(需特殊条件)
2. 空间复杂度
- 原地排序:额外空间 O(1)
- 非原地排序:需要额外数组或辅助空间
3. 稳定性(是否保持相等元素原有顺序)
- 稳定:归并、插入、冒泡、计数、基数
- 不稳定:快排、堆排、希尔、选择
4. 工程实用性
- 是否适合大规模数据
- 是否易退化
- 是否常用于标准库实现
二、十大经典排序算法总览
| 算法 | 平均时间 | 最坏时间 | 空间 | 稳定性 | 特点 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | 稳定 | 教学用,性能最差 |
| 选择排序 | O(n²) | O(n²) | O(1) | 不稳定 | 交换次数少 |
| 插入排序 | O(n²) | O(n²) | O(1) | 稳定 | 近乎有序时极快 |
| 希尔排序 | ~O(n^1.3) | O(n²) | O(1) | 不稳定 | 插入排序升级版 |
| 快速排序 | O(n log n) | O(n²) | O(log n) | 不稳定 | 实际最常用 |
| 归并排序 | O(n log n) | O(n log n) | O(n) | 稳定 | 稳定且性能稳定 |
| 堆排序 | O(n log n) | O(n log n) | O(1) | 不稳定 | 上界稳定,原地 |
| 计数排序 | O(n + k) | O(n + k) | O(k) | 稳定 | 适合整数范围小 |
| 桶排序 | O(n) | O(n²) | O(n) | 可稳定 | 依赖分布均匀 |
| 基数排序 | O(d·n) | O(d·n) | O(n) | 稳定 | 适合多位整数/字符串 |
三、十大排序算法逐一解析
1. 冒泡排序(Bubble Sort)
思想:反复比较相邻元素,逆序就交换,最大元素逐步“冒泡”到末尾。
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 稳定性:稳定
- 评价:只适合教学或极小数据量,实际工程几乎不用
2. 选择排序(Selection Sort)
思想:每轮从未排序区间选出最小值,放到当前起始位置。
- 时间复杂度:始终 O(n²)
- 空间复杂度:O(1)
- 稳定性:不稳定
- 特点:交换次数最少,但比较次数最多
3. 插入排序(Insertion Sort)
思想:维护一个有序区间,新元素向前插入合适位置。
- 平均复杂度:O(n²)
- 最好情况(近乎有序):O(n)
- 稳定性:稳定
- 工程价值:小规模排序首选,常作为高级排序的子过程
4. 希尔排序(Shell Sort)
思想:按步长分组做插入排序,逐步缩小步长直到 1。
- 时间复杂度:与步长有关,通常优于 O(n²)
- 稳定性:不稳定
- 特点:实现简单,性能介于插入与快排之间
5. 快速排序(Quick Sort)
思想:选定基准值 pivot,划分左右区间,递归排序。
- 平均复杂度:O(n log n)
- 最坏情况:O(n²)(极端退化)
- 空间复杂度:O(log n)
- 稳定性:不稳定
评价:
👉 实际工程中最快、最常用排序算法
👉 必须配合:随机 pivot / 三数取中,避免退化
6. 归并排序(Merge Sort)
思想:分治法,递归拆分后再归并两个有序数组。
- 时间复杂度:始终 O(n log n)
- 空间复杂度:O(n)
- 稳定性:稳定
工程场景:
- 需要稳定排序
- 链表排序首选
- 外部排序、磁盘排序核心算法
7. 堆排序(Heap Sort)
思想:构建最大堆,反复取堆顶最大元素。
- 时间复杂度:始终 O(n log n)
- 空间复杂度:O(1)
- 稳定性:不稳定
特点:
- 最坏情况也不退化
- 但常数较大,实际速度略慢于快排
8. 计数排序(Counting Sort)
思想:统计每个值出现次数,按顺序回填。
- 时间复杂度:O(n + k)
- 空间复杂度:O(k)
- 稳定性:稳定
限制条件:
- 只能用于整数
- 且数值范围 k 不能太大
适用场景:
- 年龄、分数、等级等小范围整数排序
9. 桶排序(Bucket Sort)
思想:把数据分到多个桶中,桶内再排序,最后合并。
- 平均复杂度:O(n)
- 最坏复杂度:O(n²)
- 稳定性:可稳定
前提条件:
- 数据分布必须较均匀
- 需要合理设计桶区间
10. 基数排序(Radix Sort)
思想:按“个位 → 十位 → 百位”逐位排序(或从高位到低位)。
- 时间复杂度:O(d · n)
- 空间复杂度:O(n)
- 稳定性:稳定
适用场景:
- 多位整数
- 字符串排序(如手机号、身份证号)
四、工程选型建议(非常重要)
在真实系统中,很少“纯用某一种排序”。常见经验如下:
🔹 小规模数据 / 局部排序
→ 插入排序
🔹 通用场景、追求性能
→ 快速排序(随机化 + 优化)
🔹 必须稳定排序
→ 归并排序 / 基数排序 / 计数排序
🔹 要求最坏时间有保证 + 原地
→ 堆排序
🔹 整数范围小、批量数据
→ 计数排序 / 基数排序
实际上,大多数标准库都采用混合排序策略:
- 小区间用插入排序
- 大区间用快排 / 归并
- 退化时切换堆排序
典型代表:C++ 的 std::sort(IntroSort)
五、总结
排序算法没有“最好”,只有“最合适”。
理解每种算法的:
- 时间复杂度
- 空间代价
- 稳定性
- 数据分布特性
才能在面试与工程中真正做到算法选型合理,系统性能可控。
如果你刚开始学算法,建议顺序掌握:
插入排序 → 快速排序 → 归并排序 → 堆排序 → 线性排序(计数 / 基数)
这已经覆盖 90% 的实际场景。
欢迎在评论区分享你最常用的排序算法,或者你在工程中遇到的排序性能问题。