zoukankan      html  css  js  c++  java
  • 看我桶排序,怎么可以更好呢

    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));
    		
    	}
    }
    
    
    所有文章未特殊说明均属原创,有误之处欢迎提出,转载随意,您喜欢就好,但请注明,谢谢!
  • 相关阅读:
    扫描线算法
    评论备份(3)
    评论备份(2)
    二分法的注意事项
    sam模板
    Machine Learning(Andrew Ng)学习笔记
    洛谷P2221 [HAOI2012]高速公路
    洛谷P3233 [HNOI2014]世界树
    P2515 [HAOI2010]软件安装
    BZOJ4293: [PA2015]Siano
  • 原文地址:https://www.cnblogs.com/nonefly/p/4833277.html
Copyright © 2011-2022 走看看