前言
桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来记得到有序序列。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是比较排序,他不受到O(n log n)下限的影响。
基本思想
桶排序的思想近乎彻底的分治思想。
桶排序假设待排序的一组数均匀独立的分布在一个范围中,并将这一范围划分成几个子范围(桶)。
然后基于某种映射函数f ,将待排序列的关键字 k 映射到第i个桶中 (即桶数组B 的下标i) ,那么该关键字k 就作为 B[i]中的元素 (每个桶B[i]都是一组大小为N/M 的序列 )。
接着将各个桶中的数据有序的合并起来 : 对每个桶B[i] 中的所有元素进行比较排序 (可以使用快排)。然后依次枚举输出 B[0]….B[M] 中的全部内容即是一个有序序列。
补充: 映射函数一般是 f = array[i] / k; k^2 = n; n是所有元素个数
为了使桶排序更加高效,我们需要做到这两点:
在额外空间充足的情况下,尽量增大桶的数量
使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
实现逻辑
设置一个定量的数组当作空桶子。
寻访序列,并且把项目一个一个放到对应的桶子去。
对每个不是空的桶子进行排序。
从不是空的桶子里把项目再放回原来的序列中。
演示
分步骤图示说明:设有数组 array = [63, 157, 189, 51, 101, 47, 141, 121, 157, 156, 194, 117, 98, 139, 67, 133, 181, 13, 28, 109],对其进行桶排序:
算法代码
这里主要是为了方便表达桶排序的思想,使用了vector,在单个桶中还用了stl的sort
1 //桶排序 2 void BucketSort(int *arr, int n) 3 { 4 int max = arr[0]; 5 for (int i = 1; i < n; i++) 6 { 7 if (arr[i] > max) 8 max = arr[i]; 9 } 10 vector<int> *bucket = new vector<int>[max / 10 + 1]; 11 for (int i = 0; i < n; i++) 12 { 13 int change = arr[i] / 10; //元素arr[i]所在的桶编号 14 bucket[change].push_back(arr[i]); 15 } 16 for (int i = 0; i < n; i++) 17 { 18 if (bucket[i].size() > 0) 19 { 20 sort(bucket[i].begin(), bucket[i].end()); //桶内排序 21 } 22 } 23 int index = 0; 24 for (int i = 0; i < n; i++) //桶遍历 25 { 26 for (int j = 0; j < bucket[i].size(); j++) //遍历桶内元素 27 { 28 arr[index++] = bucket[i][j]; 29 } 30 } 31 }
算法分析
- 平均时间复杂度:O(n + k)
- 最佳时间复杂度:O(n + k)
- 最差时间复杂度:O(n ^ 2)
- 空间复杂度:O(n * k)
- 稳定性:稳定
桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。
[参考:https://blog.csdn.net/developer1024/article/details/79770240]