一、桶排序算法的引入。
之前我们已经说过了计数排序的算法。
这个时候我们如果有这样的一个待排序数据序列:
int x[14]={-10, 2, 3, 7, 20, 23, 25, 40, 41, 43,60, 80, 90, 100};
我们如果按照计数排序的算法,那么待排序数据的范围是:-10 到 100
我们为了实现对于这个数据集的遍历,这个时候需要额外的开辟一个大小为(100- (-10)+ 1)的空间,这个时候的空间复杂度达远远超过我们的预计,也就是这个造成了空间的浪费。
所以我们可以说,计数排序还存在一个缺点:即数据里面的max 和min 的差值相比于待排序数据的数目来说,不能过大,否则会造成空间的浪费
桶排序算法相当于做了一个对于计数排序算法做了一个升级。
只不过计数排序算法计数是对于每一个排序数字进行的,而桶排序算法则将这个范围放宽,变成了一个范围。
二、桶排序算法的过程。
1、比如对于上面的一个待排序数据,我们需要把它划分为一系列的范围,从min 到 min,这就相当于有了一个一个的“桶”。
2、对应的范围的数据放入对应范围的桶里面。
3、然后对于每一个范围的数据采用其他的排序算法进行排序,使得每一个桶内部的数据都是有序的,移动到已经有序的数据集中。
上面有两个步骤比较关键:
第一个是对于桶的范围的划分,这需要一个映射的规则,如果我们把桶划分的较小,这个时候几乎每一个数据都是一个桶;了,空间浪费。如果划分的太大,所有的数据都到了一个桶里面去,相当于没有划分。
第二个是每一个桶的内部的排序算法的选择,这个影响最后总体的桶排序算法的稳定性。
三、例子
对于上面的一个待排序数据,这个时候我们已经知道了max=100, min=-10.
随后我们设计一个映射的规则,比如设计一个规则,使得 -10到 50 分为一个桶,50到100分为一个桶。
我们可以设计这样的一个规则:
ƒ(x)=x/30 - min/30
这样我们就可以把上面的数组分成了四组:
根据结果分组 | 数据 |
0 | -10, 2, 3, 7 |
1 | 20, 23 ,25 ,40, 41 |
2 | 60 |
3 | 80, 90, 100 |
然后就可与根据分组分别进行排序。
四、算法
/*算法:桶排序C++版本*/ #include <iostream> #include <vector> #include <algorithm> #include <math.h> using namespace std; //这个算法的作用是对于数组A中位于位置A[l]到A[h]中的元素分为size个桶去排序 void bksort(float A[],int l,int h,int size){ vector<float> b[size];//有size个数据,就分配size个桶 int min=A[l]; for(int i=l;i<=h;i++){//便利得到最小值 if(A[i]<min) min=A[i]; } for(int i=l;i<=h;i++){ int bi = (A[i]-min)/size;//元素A[i]的桶编号,这里修改映射规则 b[bi].push_back(A[i]);//将元素A[i]压入桶中 } for(int i=0;i<size;i++) sort(b[i].begin(),b[i].end());//桶内排序 int idx = l;//指向数组A的下标 for(int i=0;i<size;i++){//遍历桶 for(int j=0;j<b[i].size();j++){//遍历桶内元素 A[idx++] = b[i][j]; } } } int main(){ float A[] = {0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.68}; bksort(A,2,9,3); for(int i=0;i<10;i++) cout<<A[i]<<" "; }
五、复杂度分析
复杂度主要是取决于排序算法。
如果排序算法是快速排序,则可以达到Θ( n ) (大佬们的计算结果)
六、参考链接:
复杂度计算看这个:https://blog.csdn.net/bqw18744018044/article/details/81738883
算法的过程描述借鉴的是这个:https://www.jianshu.com/p/204ed43aec0c
原文地址:https://www.cnblogs.com/fantianliang/p/11881381.html