桶排序***

桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将阵列分到有限数量的桶子里。每个桶里再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。

桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。

但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。

桶式排序不再是一种基于比较的排序方法,它是一种比较巧妙的排序方式

这种排序方式需要待排序的序列满足以下两个特征:

待排序列所有的值处于一个可枚举的范围之类;

待排序列所在的这个可枚举的范围不应该太大,否则排序开销太大。

排序的具体步骤如下:

(1)对于这个可枚举范围构建一个buckets数组,用于记录“落入”每个桶中元素的个数;

(2)将(1)中得到的buckets数组重新进行计算,按如下公式重新计算:

buckets[i] = buckets[i] +buckets[i-1] (其中1<=i<buckets.length); 

桶式排序是一种非常优秀的排序算法,时间效率极高,它只要通过2轮遍历:

第1轮遍历待排数据,统计每个待排数据“落入”各桶中的个数,第2轮遍历buckets用于重新计算buckets中元素的值,

2轮遍历后就可以得到每个待排数据在有序序列中的位置,然后将各个数据项依次放入指定位置即可。

桶式排序的空间开销较大,它需要两个数组,第1个buckets数组用于记录“落入”各桶中元素的个数,进而保存各元素在有序序列中的位置,第2个数组用于缓存待排数据。

桶式排序是稳定的。

如果待排序数据的范围在0~k之间,那么它的时间复杂度是O(k+n)的

桶式排序算法速度很快,因为它的时间复杂度是O(k+n),而基于交换的排序时间上限是nlg n。

但是它的限制多,比如它只能排整形数组。

而且当k较大,而数组长度n较小,即k>>n时,辅助数组C[k+1]的空间消耗较大(要求数字要分布均匀,最大值和总个数差距不要太大)。

当数组为整形,且k和n接近时, 可以用此方法排序。(有的文章也称这种排序算法为“计数排序”)


应用

海量数据

一年的全国高考考生人数为500 万,分数使用标准分,最低100 ,最高900 ,没有小数,要求对这500 万元素的数组进行排序。
分析:对500W数据排序,如果基于比较的先进排序,平均比较次数为O(5000000*log5000000)≈1.112亿。但是我们发现,这些数据都有特殊的条件: 100=<score<=900。那么我们就可以考虑桶排序这样一个“投机取巧”的办法、让其在毫秒级别就完成500万排序。
方法:创建801(900-100)个桶。将每个考生的分数丢进f(score)=score-100的桶中。这个过程从头到尾遍历一遍数据只需要500W次。然后根据桶号大小依次将桶中数值输出,即可以得到一个有序的序列。而且可以很容易的得到100分有***人,501分有***人。
实际上,桶排序对数据的条件有特殊要求,如果上面的分数不是从100-900,而是从0-2亿,那么分配2亿个桶显然是不可能的。所以桶排序有其局限性,适合元素值集合并不大的情况。

public class BucketSortTest {
	public void bucketSort(int a[],int max,int min){
		//缓存数组,之后用于复制数组
		int temp[]=new int[a.length];
		//为桶建立数组
		// bucket用于记录待排序元素的信息
		int busket[]=new int[max-min+1];
		
		//计算每个元素在序列出现的次数
		for(int i=0;i<a.length;i++){
			busket[a[i]-min]++;
		}
		//计算“落入”各桶内的元素在有序序列中的位置
		for(int i=1;i<max-min+1;i++){
			busket[i]=busket[i]+busket[i-1];
		}
		//将数组a完全复制给数组temp
		System.arraycopy(a, 0, temp, 0, a.length);
		// 根据bucket数组中的信息将待排序列的各元素放入相应位置
		for(int i=a.length-1;i>=0;i--){
			a[--busket[temp[i]-min]]=temp[i];
		}
		
	}
	public static void main(String[] args){
		int a[]={1,8,4,6,9};
		BucketSortTest bc=new BucketSortTest();
		bc.bucketSort(a,9,1);
		for(int i=0;i<a.length;i++){
			System.out.println(a[i]);
		}
		
	}

}

刷刷笔试题~~

相邻最大差值

题目描述

请设计一个复杂度为O(n)的算法,计算一个未排序数组中排序后相邻元素的最大差值。

给定一个整数数组A和数组的大小n,请返回最大差值。保证数组元素个数大于等于2小于等于500。

测试样例:
[9,3,1,10],4
返回:6
import java.util.*;

public class MaxDivision {
    public int findMaxDivision(int[] A, int n) {
        int max=A[0];
        int min=A[0];
        //找到数组中最大、最小值
        for(int i=0;i<n;i++){
            if(A[i]>max){
                max=A[i];
            }
            if(A[i]<min){
                min=A[i];
            }
        }
        //创建桶的数组
        int bucket[]=new int[max-min+1];
        //计算每个元素在序列出现的次数
        for(int i=0;i<n;i++){
            bucket[A[i]-min]++;
        }
        int pre=1;//临时差值,默认为1
        int D_value=0;//差值
        for(int i=max-min;i>0;i--){
            if(bucket[i-1]==0){
                pre++;
            }
            if(D_value<pre){//将最大的pre值赋给D_value
                D_value=pre;
            }
            if(bucket[i-1]!=0){//遇到空的桶,pre变回原来默认值
                pre=1;
            }
            
        }
        return D_value;
    }
    public static void main(String[] args){
        int A[]={9,3,1,10};
        int n=A.length;
        MaxDivision md=new MaxDivision();
        System.out.println(md.findMaxDivision(A,n));
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值