桶排序的原理和计数排序类似,可以说是计数排序的升级版。他利用了函数映射关系,将输入的值映射到对应的桶里面去。
所以他的高效就在于这个映射函数的确定。所以需要做到如下两点:
1.在额外空间充足的情况下,尽量增大桶的数量。
2.使用映射函数能将输入的N个数据均匀的分配到K个桶中去。
此外就是对于桶中的数据元素的排序时,使用哪种比较排序的算法比较好,对性能的影响至关重要。
什么时候最快:
当输入数据可以均匀分配到每一个桶中去.
什么时候最慢:
当输入数据分配到一个桶中去.
分析过程(图片部分制作粗糙,请见谅):
根据最大值最小值分配的给这个桶切块。切成的块是23;然后通过每个数字去计算这个放到那个模块中。我这里只展示这几个数据的各部分。我们将桶的size设置为了5,也就是说每个桶只能放入5个数据元素。
也可以理解为将根据间隔为5,用数轴依次展开,就可以直到这个数大致位于哪里了。
(这里没有对倒数第二个桶进行内部排序)
参考代码:
使用的是插入排序。
public class BucketSort {
public static void main(String[] args) {
int [] a = {121, 39, 56, 20, 9, 7, 16};
System.out.println(Arrays.toString(bucketSort(a, 5)));
}
private static int[] bucketSort(int[] arr, int bucketSize) {
//arr复制
int[] a = Arrays.copyOf(arr, arr.length);
//寻找最大值和最小值
int max = a[0];
int min = a[0];
for(int i = 0; i < a.length; i ++){
if(a[i] > max){
max = a[i];
}
else if(a[i] < min){
min = a[i];
}
}
//math.floor()对浮点数向下取整
int bucketCount = (int)Math.floor((max - min) / bucketSize) + 1;
int [][] buckets = new int[bucketCount][0];
//通过映射函数将各数据映射到桶中去
for(int i = 0; i < a.length; i ++){
int index = (int)Math.floor((a[i] - min) / bucketSize);
buckets[index] = arrApend(buckets[index], a[i]);
}
int arrIndex = 0;
for(int[] bucket : buckets){
if(bucket.length <= 0){//招那些装了数据的桶
continue;
}
//对每个桶进行排序, 使用插入排序
bucket = insertSort(bucket);
for(int value : bucket){
a[arrIndex ++] = value;
}
}
return a;
}
private static int[] arrApend(int[] array, int value) {
array = Arrays.copyOf(array, array.length + 1);
array[array.length - 1] = value;
return array;
}
//插入排序 -- 一个标志位 和之前的所有元素比较
private static int[] insertSort(int [] a){
int temp = 0;
int j = 0;
for(int i = 1; i < a.length; i ++){
temp = a[i];
for(j = i; j > 0 && a[j - 1] > temp; j --){
a[j] = a[j - 1];
}
a[j] = temp;
}
return a;
}
}
输出的时候是根据桶的顺序输出数据。
结果截图:
以上就是这篇的内容,如果有什么错误或者可以改进的地方,亦或是你有什么疑惑,欢迎留言。让我们共同进步。谢谢!