思路
非整形的计数排序,将数放到桶内,先将桶内排序,再整体排序。
k 个桶,最后一个桶用来放最大值,只有 k - 1 个跨度,这 k - 1 个跨度对应 k - 1 个桶。
所以跨度为 (max - min)/(k - 1)
数对应的桶的下标为 (int)(arr[i] - min)/跨度
1.遍历原始数组 arr 找到最大值和最小值,确定桶数 k
2.创建 bucketList(ArrayList),往 bucketList 里添加 k 个 LinkedList,代表 k 个桶
3.遍历 arr,将数放入对应的桶内
4.对桶内的数做排序(可以使用JDK的集合工具类Collections.sort,时间复杂度O(nlogn))
5.遍历所有的桶,输出结果
代码
public class BucketSort{
public static double[] bucketSort(double[] arr) {
double min = arr[0];
double max = arr[0];
for(int i = 1; i < arr.length; i++){
if(arr[i] < min)
min = arr[i];
if(arr[i] > max)
max = arr[i];
}
double d = max - min;
int k = arr.length;
ArrayList<LinkedList<Double>> bucketList= new ArrayList<>(k);
for(int i = 0; i < k; i++)
bucketList.add(new LinkedList<>());
for(int i = 0; i < arr.length; i++){
bucketList.get((int)((arr[i]-min)*(k-1)/d)).add(arr[i]);
}
for(LinkedList list : bucketList)
Collections.sort(list);
double[] sortedArr = new double[arr.length];
int index = 0;
for(LinkedList<Double> list : bucketList)
for(double e: list)
sortedArr[index++] = e;
return sortedArr;
}
public static void main(String[] args){
double[] array = new double[]{5.1,5.9,8.7,6.33,6.56,3.9,9.1,2.78,1.33,4.6,7.5};
double[] sortedArr = bucketSort(array);
System.out.println(Arrays.toString(sortedArr));
}
}
复杂度分析
时间复杂度
第1、3、5步 O(n),第2步 O(k),第4步平均 O(n/k*log(n/k)*k),共 O(n + k + n*log(n/k))
假如 n = k,时间复杂度为 O(n)
最差的情况:第一个桶装了 n - 1 个数,时间复杂度 O(nlogn)
空间复杂度
不考虑返回数组的长度
k 个桶加 n 个数占用的空间 O(n+k)
稳定性分析
Collections.sort 是稳定的,桶排序也稳定
优势
特定情况下比快速排序还快,而且还是稳定的
适用场景
小范围内的大量分布较均匀的小数
本文深入解析桶排序算法,介绍其思路、代码实现、复杂度分析、稳定性及优势,并探讨其适用场景,尤其适合小范围大量分布均匀的小数排序。
420

被折叠的 条评论
为什么被折叠?



