桶排序是计数排序的升级版。通过“分配”和“收集”过程来实现排序,分治思想。
原理∶设计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)