桶排序,将待排序数据平均切分为几个区间(不同的区间之间本身就是有序的),叫做桶,每个桶各自将元素排序好,再将桶内数据合并即可完成排序。桶排序必须将数据均匀分布在桶中,如果数据全在一个桶中,排序会退化为桶内的排序类型。
计数排序可以看做是一种极端的桶排序,一个数就对应一个桶,一个桶只存放一个具体的数(而不是一个区间的数)。
import java.util.Collections;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
int[] arr = {3, 5, 6, 2, 1, 7, 4};
System.out.print("排序前:");
arrPrint(arr);
int[] result = BucketSort(arr, 4);
System.out.print("排序后:");
arrPrint(result);
}
// 桶排序
// bucketsize用于定义桶排序时候桶的size/长度,分配的桶数量则为(max - min)/bucketsize + 1
// 实例中bucketsize设为4,桶数量bucketnum则为2。
//
//
// 最大最小值max和min初始化为arr的第一个元素,遍历arr元素,把总是比max大的数赋给max,
// 把总是比min小的数赋给min。得到arr中的最大最小值max和min。
//
// 计算桶数量bucketnum = (max - min)/bucketsize + 1,桶排序是将待排序数组arr
// 中的元素,平均切分到 bucketnum 这么多个区间的排序,因此max-min计算区间范围长度,
// 在本实例中max-min=6,÷桶的长度bucketsize=4,再+1即可得到bucketnum=2(除法+1,相
// 当于除法的余数向上取整)。
// (参考计数排序中,利用-min操作,将arr[i]∈[min,max]映射到方便从0索引的
// arr[i]-min∈[0,max-min]的操作,桶排序的桶区间元素同样如此)
//
// 利用ArrayList数据类型开辟桶空间buckets,容量声明为bucketnum。
// 第一个for循环,遍历buckets,索引从0遍历到bucketnum,在buckets开辟的空间中
// 填入ArrayList<Integer>,作为桶空间来存储元素(并排序)。bucketnum为2就填入2个
// ArrayList<Integer>。
//
// 第二个for循环,遍历arr的元素,利用arr[i]-min的映射,将arr[i]∈[min,max]的分布,
// 映射到 arr[i]-min∈[0,max-min]的分布,方便我们利用桶索引来对应元素。
// 同时由于[0,max-min]已经被buckets切分为 bucketnum=2 份了,
// 所以(arr[i]-min)/bucketsize 得到的除数正好可以作为桶索引bkindex,
// 本实例中第一个bucketsize的范围是[0,bucketsize - 1],第二个桶的范围
// 是[bucketsize, max - min]。如果(arr[i]-min)/bucketsize除数为0,
// 说明arr[i]应该放入第一个桶,以此类推。得到桶索引bkindex后利用ArrayList
// get方法取得桶,add方法将元素放入桶即可:buckets.get(bkindex).add(arr[i])
//
// 第三个for循环,对每个桶各自使用排序(这里使用Collections的自带排序)。
//
// 第四个for循环组,for双循环,第一个for,索引为i,顺序遍历buckets的每一个桶
// buckets.get(i)。第二个for,索引为j,顺序遍历每个桶中的每一个元素(已被排序)
// buckets.get(i).get(j),元素存入result中即可。
// 最后返回result。
// 注:查看桶情况可插入 System.out.println(buckets.toString()) 来打印桶
private static int[] BucketSort(int[] arr, int bucketsize) {
int max = arr[0];
int min = arr[0];
for (int num: arr) {
if (max < num)
max = num;
if (min > num)
min = num;
}
int bucketnum = (max - min) / bucketsize + 1;
ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketnum);
for (int i = 0; i < bucketnum; i++) {
buckets.add(new ArrayList<Integer>());
}
for (int i = 0; i < arr.length; i++) {
int bkindex = (arr[i] - min) / bucketsize;
buckets.get(bkindex).add(arr[i]);
}
for (int i = 0; i < buckets.size(); i++) {
Collections.sort(buckets.get(i));
}
int index = 0;
int[] result = new int[arr.length];
for (int i = 0; i < buckets.size(); i++) {
for (int j = 0; j < buckets.get(i).size(); j++) {
result[index++] = buckets.get(i).get(j);
}
}
return result;
}
// 辅助函数:将int[] 打印出来
private static void arrPrint(int[] arr) {
StringBuilder str = new StringBuilder();
str.append("[");
for (int v : arr) {
str.append(v + ", ");
}
str.delete(str.length() - 2, str.length());
str.append("]");
System.out.println(str.toString());
}
}
该实例的动画演示如下: