一、桶排序概述(Bucket sort)
桶排序(Bucket Sort)是一种分治思想的排序算法,它将数组分到有限数量的桶子里,每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的数据列出来,得到有序序列。桶排序适用于当待排序的数据分布比较均匀的情况,其时间复杂度在平均情况下为O(n + k),其中n为待排序元素的数量,k为桶的数量。空间复杂度为O(n * k),因为需要额外的空间来存储桶和桶中的元素。
桶排序的基本思想是将数据映射到不同的桶中,然后对每个桶中的数据进行排序。映射函数的设计是关键,它应该能够将输入的数据均匀地分配到各个桶中。对于每个非空的桶,可以使用任何有效的排序算法进行排序,常见的有插入排序或快速排序。最后,将所有桶中的数据按照顺序连接起来,就得到了一个有序序列。
二、算法步骤(java实现)
桶排序假设待排序的一组数均匀独立的分布在一个范围中,并将这一范围划分成几个子范围(桶)。然后基于某种映射函数f ,将待排序列的关键字 k 映射到第i个桶中 (即桶数组B 的下标i) ,那么该关键字k 就作为 B[i]中的元素 (每个桶B[i]都是一组大小为N/M 的序列 )。接着将各个桶中的数据有序的合并起来 : 对每个桶B[i] 中的所有元素进行比较排序 (可以使用快排)。然后依次枚举输出 B[0]….B[M] 中的全部内容即是一个有序序列。
1.划分范围,为了分配均匀,我们需要找出数据的最大值max与最小值min,然后根据len=(max-min)/nums+1,nums为数组的长度,len为划分范围,加一是为了确保至少有一个桶,否则会出现异常;
2.确定桶的数量,桶的数量可以通过 bucks=(max-min)/len+1,bucks为桶的数量
3.分别对不同桶内的元素排序 ,排序这方面可以使用其他的排序算法,也可以使用桶的递归算法,同分治相似,但我这里直接调度java 的sort函数
4.合并数据,将所有桶中的数据按照顺序连接起来,就得到了一个有序序列。
三.测试
看完上面,如果你还感觉迷惑,你可以再看下列的举例
- 有以下数组 int a[]={21,13,24,21,18,39,78,18,20,11} 可以求出max=78,min=11,a.length=num=10,那么可以通过len=(max-min)/nums+1 得到 范围len=7,再根据bucks=(max-min)/len+1得到 bucks=10,那么如何让数据分配到桶里了,可以使用(a[i]-min)/len计算出他应该分配到哪个桶
代码如下(示例):
public class BuckSortTest {
public static void main(String[] args) {
int a[]={21,13,24,21,18,39,78,18,20,11};
bucksort(a);
for (int x:a
) {
System.out.print(x+" ");
}
}
public static void bucksort(int a[])
{
int num=a.length; //num为a的数据数量
int max=a[0]; int min=a[0]; //max,min分别为最大值与最小值
//通过Math里自带的最大值最小值算法可以求出
for (int i = 0; i < num; i++) {
max = Math.max(max, a[i]);
min=Math.min(min,a[i]);
}
int len=(max-min)/num+1;//len为桶的范围
int bucks=(max-min)/len+1; //bucks为桶的数量
List<Integer>[] arr = new List[bucks];
//分配桶
for (int i = 0; i <bucks ; i++) {
arr[i]=new ArrayList<>();
}
//把数据分配到各个桶里
for (int i = 0; i <num ; i++) {
arr[(a[i]-min)/len].add(a[i]);
}
//把每个桶里的元素进行排序
for (int i = 0; i < bucks; i++) {
arr[i].sort(null);//默认从小到大排序
}
int index=0;
//进行合并
for (int i = 0; i <bucks ; i++) {
for (int j = 0; j <arr[i].size() ; j++) {
a[index++]=arr[i].get(j);在这里插入图片描述
}
}
}
//输出结果为11 13 18 18 20 21 21 24 39 78
}
四,复杂度分析
平均时间复杂度:O(n + k)
最佳时间复杂度:O(n + k)
最差时间复杂度:O(n ^ 2)
空间复杂度:O(n * k)
稳定性:稳定
桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。
总结
1、如果数据分布不均,大量数据集中在少量桶里,桶排序就没有效果。
2、桶排序要时间就省不了空间,要空间就省不了时间,意义不大。
首先桶排序排序的内容是均匀分布的一串数字,不存在数据分布不均的问题。其次桶排序可以在时间和空间之间找一个点,使其满足两者。