import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
//桶排序
/**
* 桶排序是用空间来换取时间,类似查表,它的时间复杂度可以突破(n log n)的下限,达到线性级别
*
* 整体思想感觉特别,特别,特别!类似于构建hash表
* @author nonefly
* 2015年9月20日
*/
public class Bucket {
/**
* 其一种,如果排序的数字差距(MAX-MIN)不是很大,比如录入成绩全是[0-100]的,
* 或者数据分布都在一个范围之内
* ==================================
* 待排序数组 9 8 6 5 2 2
*
* 桶中数字 0 0 2 0 0 1 1 0 1 1 代表有几个对应下标的数
* 桶下标 0 1 2 3 4 5 6 7 8 9
*/
private static void bucketSimpleSort(int[] a, int max){
int[] arr = new int[max+1];//这个就是桶,就像hash时申请的一个连续数组
//ai代表a数组第i个,用桶中下标为ai的数字计数a[i];
//这步就像hash映射时的index = value % a.length;
//因为申请的空间肯定(如上[max+1])是大于value(即max)的,
//因此如上的hash映射也就等于index = value;
for (int ai : a) {
++arr[ai];
}//构建桶
//构建好的桶每一项arr[i],意思即是下标i的数据有arr[i]个
//下标本来就是有序的,然后从桶中谢晖原数组好了
for (int i = a.length - 1; i >= 0; ) {//原数组,倒着写回,可以只计算一次a.length,当然这点点优化并没有什么意思
for (int j = max; j >= 0; j--) {//遍历桶中数据
while(arr[j]-- > 0)//arr[j]为多少就写回几个(考虑数组中重复情况)
a[i--] = j;
}
}
//考虑分布在一段范围内情况,不是从0开始,比如[200,250]
//那么可以分配250-200+1数量的桶
//构建桶时a[i]-200就是对应下标
//写回数组时下表+200就是对应的值
}
/**
* 第二种
* hash用链表解决碰撞的做法又[很]类似另一种桶排序的设计思路:
* ①用顺序表来作为桶 (同理hash中的申请的计算出hash值对应的空间)
* ②用链表存储同一个桶中元素(hash中用链表解决碰撞)
* ③同一个桶中直接插入排序(桶中不会也不应该有很多个元素,因此直接插入效率最高)
* ④写回(和上面的一样)
*/
private static void bucketSort(int[] a,int max){
final int len = a.length;
List<LinkedList<Integer>> bucket = new ArrayList<LinkedList<Integer>>(a.length);
for (int i = 0; i < len; i++) {
bucket.add(new LinkedList<Integer>());
}//初始化桶全为空
for (int i = 0; i < len; i++) {
//忘了从哪偷来的 这种a[i] * len / (max+1)计算下标想法
//感觉挺好用,注意max+1,这样使得最大值映射不至于越界
//虽然也可以创建桶时多加一个位置
List<Integer> list = bucket.get(a[i] * len / (max+1));
int index = 0;
while(index < list.size() && list.get(index) < a[i]) ++index;//直接插入排序
list.add(index, a[i]);
}//将数据按序填充到桶中
//按序写会原数组中
int backi = 0;
for (LinkedList<Integer> linkedList : bucket) {
for (Integer integer : linkedList) {
a[backi++] = integer;
}
}
}
public static void bucketSort(int[] a){
//排序认为都是安全数字,所以传值之前应该检验
if(a == null || a.length < 1)
return;
int max = Integer.MIN_VALUE;
for (int ai : a) {
max = max > ai ? max : ai;
}
//bucketSimpleSort(a, max);//简单桶
bucketSimpleSort(a, max);
}
public static void main(String[] args) {
int a[] = {1,2,3,4,5,6,70,18,9,0,9,87,6,54};
bucketSort(a);
System.out.println(Arrays.toString(a));
}
}