17370845950

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

计数排序适合什么数据范围

计数排序只适用于整数,且值域不能太大——理想情况是 max - min 在几万以内。如果数组里有 INT_MAX0,直接开桶会崩溃或超内存。实际用前先检查: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

原地排序还是额外输出数组

计数排序天然不适合真·原地排序(无法避免桶数组),但可以避免二次遍历输入数组来填结果。常见写法是先算前缀和,再从右往左反向填入输出数组,保证稳定性。

示例关键片段:

vector count(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 往往只在特定数据下触发,比逻辑错误更难定位。