桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这三点:
1、在额外空间充足的情况下,尽量增大桶的数量
2、桶的尺寸不能小于重复数据数量
3、使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
工作的原理是将数组分到有限数量的有序桶里,每个桶有不同的大小范围,不同的数据放到对应范围的桶中,每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
桶排序具体步骤如下:
1、确定桶的大小;
2、找出待排序数组中的最大值和最小值;
3、根据最大最小值及桶的尺寸计算需要桶的数量;
4、遍历待排序数组,将元素放入对应桶中;
5、遍历每个桶,对桶中元素排序,排序后回填至待排序数组完成排序
元素分配到桶
桶中元素排序
执行过程请移步文章末尾:执行过程。
当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
代码实现:
package com.algorithm.sort;
import java.util.Arrays;
/**
* @author LuoFei
* @className: BucketSort
* @projectName algorithm
* @description: TODO
* @date 2023/3/1 15:18
*/
public class BucketSort {
public static void bucketSort(int[] arr, int size) {
System.out.println("桶大小:"+size);
if (arr.length <= 1) {
System.out.println("数组小于2位,无需排序");
return;
}
int minValue = arr[0];
int maxValue = arr[0];
System.out.println("遍历数组,查找最大和最小值");
for (int value : arr) {
if (value < minValue) {
minValue = value;
}
if (value > maxValue) {
maxValue = value;
}
}
System.out.println("最大值:"+maxValue+"; 最小值:"+minValue);
int bucketCount = (int) (Math.floor((maxValue-minValue)/size) + 1);
System.out.println("分配桶的数量:"+bucketCount);
System.out.println("根据桶的数量,创建二维数组,一维为桶编号,二维为桶内数据");
int[][] buckets = new int[bucketCount][0];
System.out.println("遍历数组,将数组中元素放入对应桶中。");
for (int i = 0; i < arr.length; i++) {
int index = (int) Math.floor((arr[i]-minValue)/size);
buckets[index] = arrAppend(buckets[index], arr[i]);
System.out.println("将数组元素:arr["+i+"]="+arr[i]+", 放入"+index+"号桶");
}
System.out.println("桶中数据如下:");
for (int i=0; i< buckets.length; i++) {
int[] bucket = buckets[i];
System.out.println(i+"号桶数据:"+Arrays.toString(bucket));
}
System.out.println("------------------开始排序------------------");
int arrIndex = 0;
System.out.println("遍历桶,并对每个桶中数据排序后填入原数组");
for (int i=0; i< buckets.length; i++) {
int[] bucket = buckets[i];
System.out.println("对"+i+"号桶数据处理变,原数据:"+Arrays.toString(bucket));
if (bucket.length <= 0) {
System.out.println(i+"号桶无数据,继续下一个。");
continue;
}
System.out.println("*******************对"+i+"号桶进行插入排序*****************");
InsertionSort.insertionSort(bucket);
System.out.println("*******************"+i+"号桶排序结束*****************************");
System.out.println(i+"号桶新数据:"+Arrays.toString(bucket));
System.out.println("遍历"+i+"号桶,将数据填入待排序数组");
for (int value : bucket) {
arr[arrIndex++] = value;
}
System.out.println("新数组:"+Arrays.toString(arr));
}
}
public static int[] arrAppend(int[] arr, int value) {
arr = Arrays.copyOf(arr, arr.length+1);
arr[arr.length-1] = value;
return arr;
}
public static void main(String[] args) {
int[] arr = {5, 2, 8, 3, 9, 1};
System.out.println("桶排序");
System.out.println("初始数组:"+ Arrays.toString(arr));
System.out.println("==============开始桶排序===============");
bucketSort(arr, 3);
System.out.println("==============桶排序完成===============");
System.out.println("最终数组"+Arrays.toString(arr));
}
}
执行过程:
桶排序
初始数组:[5, 2, 8, 3, 9, 1]
==============开始桶排序===============
桶大小:3
遍历数组,查找最大和最小值
最大值:9; 最小值:1
分配桶的数量:3
根据桶的数量,创建二维数组,一维为桶编号,二维为桶内数据
遍历数组,将数组中元素放入对应桶中。
将数组元素:arr[0]=5, 放入1号桶
将数组元素:arr[1]=2, 放入0号桶
将数组元素:arr[2]=8, 放入2号桶
将数组元素:arr[3]=3, 放入0号桶
将数组元素:arr[4]=9, 放入2号桶
将数组元素:arr[5]=1, 放入0号桶
桶中数据如下:
0号桶数据:[2, 3, 1]
1号桶数据:[5]
2号桶数据:[8, 9]
------------------开始排序------------------
遍历桶,并对每个桶中数据排序后填入原数组
对0号桶数据处理变,原数据:[2, 3, 1]
*******************对0号桶进行插入排序*****************
第1轮
选择1号位数字“3”为基准数字,与前面已排序数字比较
比较:[0, 1], 顺序正确
基准数字”3“插入1号位置
新数组:[2, 3, 1]
------------------------------------------
第2轮
选择2号位数字“1”为基准数字,与前面已排序数字比较
比较:[1, 2], 1 号位后移一位;
比较:[0, 2], 0 号位后移一位;
基准数字”1“插入0号位置
新数组:[1, 2, 3]
------------------------------------------
*******************0号桶排序结束*****************************
0号桶新数据:[1, 2, 3]
遍历0号桶,将数据填入待排序数组
新数组:[1, 2, 3, 3, 9, 1]
对1号桶数据处理变,原数据:[5]
*******************对1号桶进行插入排序*****************
*******************1号桶排序结束*****************************
1号桶新数据:[5]
遍历1号桶,将数据填入待排序数组
新数组:[1, 2, 3, 5, 9, 1]
对2号桶数据处理变,原数据:[8, 9]
*******************对2号桶进行插入排序*****************
第1轮
选择1号位数字“9”为基准数字,与前面已排序数字比较
比较:[0, 1], 顺序正确
基准数字”9“插入1号位置
新数组:[8, 9]
------------------------------------------
*******************2号桶排序结束*****************************
2号桶新数据:[8, 9]
遍历2号桶,将数据填入待排序数组
新数组:[1, 2, 3, 5, 8, 9]
==============桶排序完成===============
最终数组[1, 2, 3, 5, 8, 9]