桶排序(BucketSort)
一、思想
一句话总结:划分多个范围相同的区间,每个自区间自排序,最后合并。
(适用于数据量大的时候,可以通过空间换时间)
桶排序是计数排序的扩展版本,计数排序可以看成每个桶只存储相同元素,而桶排序每个桶存储一定范围的元素,通过映射函数,将待排序数组中的元素映射到各个对应的桶中,对每个桶中的元素进行排序,最后将非空桶中的元素逐个放入原序列中。
桶排序需要尽量保证元素分散均匀,否则当所有数据集中在同一个桶中时,桶排序失效。
二、图解方案
三、算法实现:
1.找出待排序数组中的最大值max、最小值min
2.我们使用 动态数组ArrayList 作为桶,桶里放的元素也用 ArrayList 存储。桶的数量为(max-min)/arr.length+1
3.遍历数组 arr,计算每个元素 arr[i] 放的桶
4.每个桶各自排序
5.遍历桶数组,把排序好的元素放进输出数组
public static int[] bucketSort1(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
//计算最大值与最小值
int max = Integer.MIN_VALUE;// -2147483648
int min = Integer.MAX_VALUE; //2147483647
for(int i = 0;i < arr.length;i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
//计算桶的数量
int bucketNum = (max - min) /arr.length+1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for (int i = 0; i < bucketNum; i++) {
bucketArr.add(new ArrayList<Integer>());
}
//将每个元素放入桶
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min)/(arr.length);
bucketArr.get(num).add(arr[i]);
}
//对每个桶进行排序
for (int i = 0; i < bucketArr.size(); i++) {
Collections.sort(bucketArr.get(i));
}
//将桶中元素赋值到原序列
int index = 0;
for (int i = 0; i < bucketArr.size(); i++) {
for (int j = 0; j < bucketArr.get(i).size(); j++) {
arr[index++] = bucketArr.get(i).get(j);
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {18,11,28,45,23,50};
int[] res = bucketSort1(arr);
for (int i = 0; i < res.length; i++) {
System.out.print(arr[i] + " ");
}
四、时间复杂度:
当输入的元素是0到k之间的整数时
平均时间复杂度:O(n + k)
最佳时间复杂度:O(n + k)
最差时间复杂度:O(n ^ 2)
空间复杂度:O(n * k)
稳定性:稳定
桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。