计数排序适合值域较小的整数(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)。
标准计数排序常假设输入是非负整数,但真实场景常有负数。解决办法是做偏移:找出 min_val,把所有数减去它,映射到 [0, max-min] 区间。
arr[i] - min_val
index + min_val
max_val - min_val + 1,别漏掉 +1
计数排序天然不适合真·原地排序(无法避免桶数组),但可以避免二次遍历输入数组来填结果。常见写法是先算前缀和,再从右往左反向填入输出数组,保证稳定性。
示例关键片段:
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 平均 O(n log n),但常数极小、缓存友好、支持任意类型和自定义比较。手写计数排序只在以下情况值得考虑:
std::sort 占比高漏掉范围校验或没处理负数,上线后遇到异常输入就会访问越界——这类 bug 往往只在特定数据下触发,比逻辑错误更难定位。