非比较排序
913 字
5 分钟
非比较排序
非比较排序
比较类排序有理论下界 O(n log n),非比较排序通过不比较元素大小来突破这个下界。代表算法有基数排序和计数排序。
基数排序
核心思想
- 非比较排序:不比较关键字大小,而是按关键字的每一”位”做分配与收集
- 多关键字排序:将单个关键字拆分为 d 位,每位看作一个子关键字
- 借助稳定的”分配-收集”:对每一位使用桶(队列)完成一趟排序,d 趟后整体有序
算法步骤
每一趟包含两个步骤:
- 分配:扫描序列,根据当前位的值将元素放入对应的桶(队列 Q₀~Q_{r-1})
- 收集:按桶编号 0→r-1 依次将各桶元素取出,串接成新序列
重复 d 趟(从最低位到最高位),排序完成。
LSD vs MSD
| 方式 | 处理顺序 | 特点 |
|---|---|---|
| LSD | 从最低位到最高位 | 实现简单,408 考试默认方式 |
| MSD | 从最高位到最低位 | 需递归对每个桶内部排序,较复杂 |
排序过程示例
序列 {278, 109, 063, 930, 589, 184, 505, 269, 008, 083}(LSD, d=3, r=10):
| 趟次 | 按位 | 收集结果 |
|---|---|---|
| 第 1 趟 | 个位 | 930, 063, 083, 184, 505, 278, 008, 109, 589, 269 |
| 第 2 趟 | 十位 | 505, 008, 109, 930, 063, 269, 278, 083, 184, 589 |
| 第 3 趟 | 百位 | 008, 063, 083, 109, 184, 269, 278, 505, 589, 930 |
复杂度
| 指标 | 值 |
|---|---|
| 时间 | O(d(n+r)) |
| 空间 | O(r) |
| 稳定性 | 稳定 |
⚠️ 易错:基数排序有 LSD 和 MSD 两种。408 默认考 LSD——从最低位开始排,要求每趟分配使用的排序算法是稳定的。
计数排序
核心思想
对每个元素 x,统计比 x 小的元素有多少个,就能直接确定 x 在排序结果中的位置。
算法步骤
- 计数:创建计数数组 C[0..k],统计每个值出现的次数
- 累加:对 C 做前缀和——C[i] 表示值 ≤ i 的元素总个数
- 输出:从后往前扫描 A,根据 C 确定每个元素的最终位置
代码实现
void CountingSort(int A[], int B[], int n, int k) { int C[k + 1]; memset(C, 0, sizeof(C)); for (int i = 0; i < n; i++) // 计数 C[A[i]]++; for (int i = 1; i <= k; i++) // 前缀和 C[i] += C[i - 1]; for (int i = n - 1; i >= 0; i--) { // 从后往前保证稳定 B[C[A[i]] - 1] = A[i]; C[A[i]]--; }}复杂度
| 指标 | 值 |
|---|---|
| 时间 | O(n+k) |
| 空间 | O(n+k) |
| 稳定性 | 稳定 |
| 适用条件 | 整数且取值范围 k 不太大 |
⚠️ 易错:计数排序的稳定性依赖于第 3 步从后往前扫描。如果从前往后,相同值的元素会被反序放置。
⚠️ 易错:计数排序只适合顺序存储,因为需要根据计数值直接定位下标。
考研高频考点
- ⭐ 基数排序是非比较排序,不受 O(n log n) 下界限制
- ⭐ 时间复杂度 O(d(n+r)) 中各参数的含义及计算
- ⭐ LSD 分配与收集过程手动模拟(大题)
- ⭐ 计数排序 O(n+k)
- ⭐ 从后往前扫描保证稳定性的原理
- 计数排序与基数排序的关系(基数排序每趟底层可用计数排序实现)
- 适用场景:关键字位数少、记录数量多
关联页面
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
排序基础概念
数据结构2026-07-07
2
外部排序
数据结构2026-07-07
3
交换排序
数据结构2026-07-07
4
插入排序
数据结构2026-07-07
5
选择排序
数据结构2026-07-07
随机文章随机推荐










