引言
本篇是排序算法的第八篇,桶排序,桶排序是计数排序的升级版。
1、算法步骤
1、设定一个基准,将待排序的数字按照一定范围,从小到大的平均分在N个桶中,此时桶已经排好序,桶中的元素还未排序;
2、将桶中的元素进行排序。
3、将每个桶按照从小到大的编号,依次取出里面的元素放入到待排序数组中,排序完成。
2、时间复杂度
平均时间复杂度O(n + k)
3、算法实现
public class BucketSort {
public static void main(String[] args) {
int[] numbers = {
12,2,24,30,6,16};
int[] result = BucketSort.bucketSort(numbers,3);
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < result.length; i++) {
stringBuffer.append(result[i] + " ");
}
System.out.println(stringBuffer.toString());
}
//bucketSize是初始化桶个数的一个基准值
public static int[] bucketSort(int[] arg,int bucketSize){
if(arg.length == 0){
return arg;
}
int maxValue = arg[0];
int minVaule = arg[0];
for (int i = 1; i < arg.length; i++) {
if(arg[i] < minVaule){
minVaule = arg[i];
} else if(arg[i] > maxValue){
maxValue = arg[i];
}
}
//桶的数量
int bucketCount = (int)Math.floor((maxValue - minVaule) / bucketSize) + 1;
//初始化一个二维数组,横坐标是桶的编号,纵坐标是值
int[][] buckets = new int[bucketCount][0];
//将待排序值按照一定规则映射到数组中
for (int i = 0; i < arg.length; i++) {
int index = (int)Math.floor((arg[i] - minVaule) / bucketSize);
buckets[index] = arrAppend(buckets[index], arg[i]);
}
int arrIndex = 0;
//循环每个桶
for (int i = 0; i < buckets.length; i++) {
if(buckets[i].length <= 0){
continue;
}
//将每个桶中的数组按照插入排序算法进行排序
int[] bucket = insertSort(buckets[i]);
//按照桶的顺序,将桶中排好序的值,依次放入到数组中
for (int j = 0; j < bucket.length; j++) {
arg[arrIndex++] = bucket[j];
}
}
return arg;
}
//插入排序算法
public static int[] insertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
// 记录要插入的数据
int tmp = arr[i];
// 从已经排序的序列最右边的开始比较,找到比其小的数
int j = i;
while (j > 0 && tmp < arr[j - 1]) {
arr[j] = arr[j - 1];
j--;
}
// 存在比其小的数,插入
if (j != i) {
arr[j] = tmp;
}
}
return arr;
}
//自动扩容,并保存数据
public static int[] arrAppend(int[] arr,int value){
arr = Arrays.copyOf(arr, arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}
结束语
桶排序的高效与否的关键就在于这个映射函数的确定,在空间足够的时候,尽量增加桶的数量,将数据尽量均匀的分到K个桶中。