計數排序是非比較排序的代表,在特定條件下實現 O(n+k) 線性時間,打破了比較排序 Ω(n log n) 的下界。適用於整數、範圍已知、範圍較小的數據。
[min, max] 已知且 k = max - min + 1 較小k = O(n) 才有優勢count[val - min]++count[i] 表示 ≤ i 的元素個數,即輸出位置count[val-min]-- 確定位置,保證穩定性#include <stdlib.h>
#include <string.h>
void counting_sort(int arr[], int n, int min_val, int max_val) {
int k = max_val - min_val + 1;
int *count = calloc(k, sizeof(int));
int *output = malloc(n * sizeof(int));
// 1. 統計頻次
for (int i = 0; i < n; i++)
count[arr[i] - min_val]++;
// 2. 前綴和:count[i] 存儲 ≤ i 的元素數量
for (int i = 1; i < k; i++)
count[i] += count[i-1];
// 3. 反向填充(保證穩定性)
for (int i = n-1; i >= 0; i--) {
int idx = arr[i] - min_val;
output[--count[idx]] = arr[i];
}
memcpy(arr, output, n * sizeof(int));
free(count);
free(output);
}
// 便捷版:自動計算範圍
void counting_sort_auto(int arr[], int n) {
if (n <= 1) return;
int min_val = arr[0], max_val = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] < min_val) min_val = arr[i];
if (arr[i] > max_val) max_val = arr[i];
}
counting_sort(arr, n, min_val, max_val);
}
前綴和 count[x] 表示「≤ x 的元素最後位置 + 1」。反向遍歷時,相同值的後出現者先放置,保證相對順序不變 → 穩定排序。
通過 val - min_val 映射到非負索引,無需額外邏輯。
若無需穩定性,可正向填充並直接覆蓋原數組,省去 output 數組。
| 指標 | 複雜度 | 說明 |
|---|---|---|
| 時間 | O(n + k) | n=元素數,k=值域大小 |
| 空間 | O(n + k) | count + output 數組 |
| 穩定性 | 穩定 | 反向填充保證 |
將計數排序作為子程序,按位(LSD)或最高位優先(MSD)多輪排序,擴展到大範圍整數、字符串。
將值域劃分為若干桶,桶內再排序。適合均勻分布的浮點數。
數據量: 10,000,000 隨機整數 [0, 10000] 計數排序: ~0.08s (O(n+k), k=10001) 快速排序: ~0.45s (O(n log n)) std::sort: ~0.38s
當 k < n log n 時,計數排序顯著優於比較排序。
計數排序展示了「利用數據特徵突破理論下界」的算法智慧。在合適場景下,它是性能優化的銀彈;濫用則會帶來災難性的空間開銷。理解其適用邊界,是高性能計算工程師的基本功。