桶排序是计数排序的升级版。通过“分配”和“收集”过程来实现排序,分治思想。
原理∶设计k个桶( bucket )(编号O~k-1),然后将n个输入数分布到各个桶中去,对各个桶中的数进行排序,然后按照次序把各个桶中的元素列出来即可。
适用范围:均匀分配
第一种写法:
public class BucketSort {
public static void main(String[] args) {
int[] arr = {18, 11, 28, 45, 23, 50};
int[] res = bucketSort(arr);
for (int i = 0; i < res.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static int[] bucketSort(int[] arr){
// 计算最大值与最小值
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i = 0; i < arr.length; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
// 计算桶的数量
int bucketNum = (max - min) / arr.length + 1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<ArrayList<Integer>>(bucketNum);
for(int i = 0; i < bucketNum; i++){
bucketArr.add(new ArrayList<Integer>());
}
// 将每个元素放入桶
for(int i = 0; i < arr.length; i++){
int num = (arr[i] - min) / (arr.length);
bucketArr.get(num).add(arr[i]);
}
// 对每个桶进行排序
for(int i = 0; i < bucketArr.size(); i++){
Collections.sort(bucketArr.get(i));
}
// 将桶中的元素赋值到原序列
int index = 0;
for(int i = 0; i < bucketArr.size(); i++){
for(int j = 0; j < bucketArr.get(i).size(); j++){
arr[index++] = bucketArr.get(i).get(j);
}
}
return arr;
}
}
第二种写法:
public class BucketSort {
static final int DEFAULT_INITIAL_CAPACITY = 10; // 默认 10,这里具体看你的数据的量
private static void bucketSort(int[] arr) {
// 新建一个桶的集合
ArrayList<LinkedList<Integer>> buckets = new ArrayList<LinkedList<Integer>>();
for (int i = 0; i < DEFAULT_INITIAL_CAPACITY; i++) {
// 新建一个桶,并将其添加到桶的集合中去。
// 由于桶内元素会频繁的插入,所以选择 LinkedList 作为桶的数据结构
buckets.add(new LinkedList<Integer>());
}
// 将输入数据全部放入桶中并完成排序
for (Integer data : arr) {
int index = getBucketIndex(data);
insertSort(buckets.get(index), data);
}
// 将桶中元素全部取出来并放入 arr 中输出
int index = 0;
for (LinkedList<Integer> bucket : buckets) {
for (Integer data : bucket) {
arr[index++] = data;
}
}
}
/**
* 我们选择插入排序作为桶内元素排序的方法 每当有一个新元素到来时,我们都调用该方法将其插入到恰当的位置
* @param bucket
* @param data
*/
private static void insertSort(LinkedList<Integer> bucket, Integer data) {
ListIterator<Integer> iterator = bucket.listIterator();
boolean insertFlag = true;
while (iterator.hasNext()) {
if (data <= iterator.next()) {
iterator.previous(); // 把迭代器的位置偏移回上一个位置
iterator.add(data); // 把数据插入到迭代器的当前位置
insertFlag = false;
break;
}
}
if (insertFlag) {
bucket.add(data); // 否则把数据插入到链表末端
}
}
/**
* 计算得到输入元素应该放到哪个桶内
* @param data
* @return
*/
private static int getBucketIndex(Integer data) {
// 这里例子写的比较简单,仅使用对10取整作为其桶的索引值
// 实际开发中需要根据场景具体设计
return data / DEFAULT_INITIAL_CAPACITY;
}
public static void main(String[] args) {
int[] arr = {1,28,29,3,21,11,7,6,18};
bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
}
时间复杂度:时间复杂度:O(N + C)