计数排序适合值域较小的整数(max−min≤10⁶),需偏移处理负数,时间复杂度O(n+k),空间O(k),非原地但可稳定排序;仅当输入范围确定且性能瓶颈明显时优于std::sort。

计数排序适合什么数据范围
计数排序只适用于整数,且值域不能太大——理想情况是 max - min 在几万以内。如果数组里有 INT_MAX 和 0,直接开桶会崩溃或超内存。实际用前先检查:if (max_val - min_val > 1e6) return;。
它不比较元素,而是统计每个值出现次数,所以时间复杂度稳定是 O(n + k)(k 是值域大小),但空间代价是 O(k)。
怎么处理负数和非从 0 开始的整数
标准计数排序常假设输入是非负整数,但真实场景常有负数。解决办法是做偏移:找出 min_val,把所有数减去它,映射到 [0, max-min] 区间。
- 统计时下标为
arr[i] - min_val - 还原时结果值为
index + min_val - 桶数组大小必须是
max_val - min_val + 1,别漏掉+1
原地排序还是额外输出数组
计数排序天然不适合真·原地排序(无法避免桶数组),但可以避免二次遍历输入数组来填结果。常见写法是先算前缀和,再从右往左反向填入输出数组,保证稳定性。
立即学习“C++免费学习笔记(深入)”;
示例关键片段:
vectorcount(max_val - min_val + 1, 0); for (int x : arr) count[x - min_val]++; // 前缀和:count[i] 表示 ≤ (min_val + i) 的元素个数 for (int i = 1; i < count.size(); i++) count[i] += count[i-1]; vector output(arr.size()); // 从后往前,保持相等元素的相对顺序 for (int i = arr.size() - 1; i >= 0; i--) { int idx = arr[i] - min_val; output[--count[idx]] = arr[i]; }
和 std::sort 比,什么时候该用手写计数排序
不是“更快就一定更好”。std::sort 平均 O(n log n),但常数极小、缓存友好、支持任意类型和自定义比较。手写计数排序只在以下情况值得考虑:
- 输入确定是小范围整数(比如成绩 0–100、年份 1970–2030)
-
性能瓶颈真卡在排序上,且 profiler 显示
std::sort占比高 - 你控制输入来源,能确保无非法值(比如越界、NaN、非整数)
漏掉范围校验或没处理负数,上线后遇到异常输入就会访问越界——这类 bug 往往只在特定数据下触发,比逻辑错误更难定位。










