(暂无)
桶排序(Bucket Sort)是一种非比较排序算法。其核心思想是:将待排序元素按照某种映射规则分配到若干个"桶"中,每个桶内部单独排序,最后按桶的顺序依次收集元素。
当数据分布比较均匀时,桶排序可以达到 O(n) 的时间复杂度,打破了基于比较的排序 O(n log n) 的下界。
前提条件:需要知道数据的范围,且数据分布相对均匀。
当数据范围不大时(如 0 ~ 10^6),可以直接用数组下标作为桶:
1#include <bits/stdc++.h>
2using namespace std;
3
4int cnt[1000001]; // 每个值出现的次数
5
6int main() {
7 int n;
8 scanf("%d", &n);
9 int a[100005];
10 int maxVal = 0;
11 for (int i = 0; i < n; i++) {
12 scanf("%d", &a[i]);
13 cnt[a[i]]++;
14 maxVal = max(maxVal, a[i]);
15 }
16
17 // 按桶的顺序收集
18 int idx = 0;
19 for (int v = 0; v <= maxVal; v++) {
20 while (cnt[v] > 0) {
21 a[idx++] = v;
22 cnt[v]--;
23 }
24 }
25
26 for (int i = 0; i < n; i++) printf("%d ", a[i]);
27 return 0;
28}当数据范围很大或是浮点数时,使用多个桶来分段:
1#include <bits/stdc++.h>
2using namespace std;
3
4void bucketSort(vector<double>& a) {
5 int n = a.size();
6 if (n <= 1) return;
7
8 // 找到最大值和最小值
9 double minVal = *min_element(a.begin(), a.end());
10 double maxVal = *max_element(a.begin(), a.end());
11
12 // 创建 n 个桶
13 int bucketCount = n;
14 double bucketRange = (maxVal - minVal) / bucketCount + 1e-9;
15 vector<vector<double>> buckets(bucketCount);
16
17 // 分配元素到桶中
18 for (double x : a) {
19 int idx = (int)((x - minVal) / bucketRange);
20 if (idx >= bucketCount) idx = bucketCount - 1;
21 buckets[idx].push_back(x);
22 }
23
24 // 桶内排序
25 for (auto& bucket : buckets) {
26 sort(bucket.begin(), bucket.end());
27 }
28
29 // 收集结果
30 int k = 0;
31 for (auto& bucket : buckets) {
32 for (double x : bucket) {
33 a[k++] = x;
34 }
35 }
36}
37
38int main() {
39 vector<double> a = {0.42, 0.32, 0.23, 0.52, 0.25, 0.47, 0.51};
40 bucketSort(a);
41 for (double x : a) printf("%.2f ", x);
42 // 输出: 0.23 0.25 0.32 0.42 0.47 0.51 0.52
43 return 0;
44}以 [0.42, 0.32, 0.23, 0.52, 0.25, 0.47, 0.51](7 个元素)为例,使用 5 个桶:
桶的范围划分(0.23 ~ 0.52,每桶宽度约 0.06):
| 桶编号 | 范围 | 分配的元素 | 桶内排序后 |
|---|---|---|---|
| 0 | [0.23, 0.29) | 0.23, 0.25 | 0.23, 0.25 |
| 1 | [0.29, 0.35) | 0.32 | 0.32 |
| 2 | [0.35, 0.41) | (空) | (空) |
| 3 | [0.41, 0.47) | 0.42 | 0.42 |
| 4 | [0.47, 0.53] | 0.52, 0.47, 0.51 | 0.47, 0.51, 0.52 |
按桶的顺序收集:[0.23, 0.25, 0.32, 0.42, 0.47, 0.51, 0.52]
判断是否适合使用桶排序:
桶排序的变体:
竞赛中的应用场景:
| 特性 | 桶排序 |
|---|---|
| 时间复杂度(最好/平均) | O(n + k),k 为桶数量 |
| 时间复杂度(最坏) | O(n²),所有元素落入同一个桶 |
| 空间复杂度 | O(n + k) |
| 稳定性 | 取决于桶内排序算法(可以做到稳定) |
| 适用场景 | 数据范围已知、分布均匀 |
与比较排序的对比:
| 排序类型 | 下界 | 条件 |
|---|---|---|
| 基于比较的排序 | O(n log n) | 无额外条件 |
| 桶排序/计数排序/基数排序 | O(n) | 需要数据范围/分布信息 |
桶排序打破了 O(n log n) 的排序下界,但代价是需要额外的空间和对数据的先验知识。在竞赛中,桶排序常常以"计数排序"的形式出现,用于值域较小的场景。
