跳过并跳转到主要内容
BigO

桶排序

桶排序将数据按数值范围划分到若干个桶内,每个桶内部再使用其他排序算法排序,最后依次合并所有桶的元素得到有序序列;平均时间复杂度 O(n),适合数据分布均匀的场景,需要额外开辟桶空间,属于稳定排序。

基础算法,排序1分钟阅读

桶排序(Bucket Sort) 是一种分治思想的排序算法。它的核心理念是将数组分到有限数量的 桶(Bucket) 里,每个桶再分别进行排序(可以使用其他排序算法,或继续递归使用桶排序),最后按顺序把各个桶里的元素合并起来。

如果输入的数据分布均匀,桶排序可以达到线性时间复杂度 O(n)O(n)。

桶排序的具体步骤可以分为以下 4 步:

  1. 初始化桶:根据待排序数据的范围,确定桶的数量和区间大小,创建空桶。
  2. 分配数据:遍历原始数组,利用映射函数(Hash 函数)计算出每个元素应该放入哪一个桶中。
    确定桶规模并分发元素
    先获取数组最值计算桶总数,通过索引映射把原始元素分散到各个桶中;此时桶内数据无序,后续需要对每个桶内部排序。
  3. 桶内排序:对每个非空的桶独立进行排序(通常使用插入排序、快速排序等)。
    桶内排序
    分发完成后每个桶内部仍是乱序;选用插入排序对每个桶独立排序。桶内数据量小,插入排序效率表现较好;全部桶排序完成后,下一步依次拼接所有桶即可得到完整有序数组。
  4. 合并结果:按照桶的顺序,依次取出各个桶中的元素,组合成最终的有序序列。
    合并输出
    各桶已经有序,桶与桶之间天然满足大小关系;直接按桶顺序依次取出全部元素,不需要跨桶比较,即可得到全局有序数组。

指标复杂度 / 属性说明
最好时间复杂度O(n+k)O(n + k)数据均匀分布,每个桶内元素极少,排序耗时接近 O(1)O(1)
最坏时间复杂度O(n2)O(n^2)所有元素都被分配到了同一个桶中(取决于桶内使用的排序算法)
平均时间复杂度O(n+k)O(n + k)nn 为元素个数,kk 为桶的数量
空间复杂度O(n+k)O(n + k)需要额外的空间来存储桶及桶内的元素
稳定性稳定是否稳定取决于桶内排序所使用的算法(如使用插入排序则稳定)

以下是一个用 C++ 实现的典型桶排序(桶内使用内置排序/插入排序思想):

#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::sort
// 桶排序函数
void bucketSort(std::vector<float>& arr) {
int n = arr.size();
if (n <= 1) return;
// 1. 创建 n 个空桶
std::vector<std::vector<float>> buckets(n);
// 2. 将数组中的元素分配到不同的桶中
for (int i = 0; i < n; ++i) {
// 利用映射函数:index = n * arr[i] 计算桶索引
int bucketIndex = n * arr[i];
// 边界防护:防止元素等于 1.0 时索引越界
if (bucketIndex >= n) {
bucketIndex = n - 1;
}
buckets[bucketIndex].push_back(arr[i]);
}
// 3. 对每个桶分别进行排序
for (int i = 0; i < n; ++i) {
// std::sort 底层在元素较少时会自动使用插入排序
std::sort(buckets[i].begin(), buckets[i].end());
}
// 4. 将所有桶中的元素依次拼接回原数组
int index = 0;
for (int i = 0; i < n; ++i) {
for (float val : buckets[i]) {
arr[index++] = val;
}
}
}
int main() {
// 测试数据(取值范围在 0 ~ 1 之间的浮点数)
std::vector<float> arr = {0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434};
std::cout << "排序前: ";
for (float x : arr) {
std::cout << x << " ";
}
std::cout << "\n";
// 执行桶排序
bucketSort(arr);
std::cout << "排序后: ";
for (float x : arr) {
std::cout << x << " ";
}
std::cout << "\n";
return 0;
}

  • 数据分布均匀:如在 [0,1)[0, 1) 浮点数范围内均匀分布的数据。
  • 已知数据边界:能够明确算出数据的极值范围,从而设置合理的映射函数。

  • 对数据分布敏感:如果数据极度倾斜(比如 99% 的数据都挤在一个桶里),桶排序会退化为普通的桶内排序算法(如 O(n2)O(n^2) 或 O(nlog⁡n)O(n \log n))。
  • 额外空间开销大:需要预先分配桶空间,对于极其稀疏的数据可能会浪费大量的内存。

  • 计数排序(Counting Sort):可以看作是桶排序的特例,即每个桶的区间大小正好为 1。只适用于整数且范围较小的情况。
  • 基数排序(Radix Sort):按“位”(个位、十位、百位)来进行多轮桶排序,适合处理位数固定的大整数或字符串。

© 2026 三七开 · 一方通行,只管向前。

旅途由 Astro 驱动 · 主题 Chirping Astro