Java内部排序(九)-(桶式排序)

桶式排序不再是一种基于比较的排序方法,他是一种非常巧妙的排序方式,但这种排序方式需要满足下面两个要求:

1、待排序列的所有值处于一个可枚举的范围内。

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

下面将介绍桶式排序的详细过程,以如下待排序列为例 。

5, 4, 2, 4, 1

这个待排序列处于0,1,2,3,4,5这个可枚举的范围内,而且枚举范围很小,正适合桶式排序。

具体步骤如下:

1、对这个可枚举范围构建一个 buckets 数组,用于记录“落入”每个桶中的元素个数,于是可以得到如下图所示的buckets数组:

 buckets数组

2、按如下公式对上图所示的buckets数组的元素进行重新计算。

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


即可得到如下图所示的buckets数组:

原buckets数组:

buckets数组:


桶式排序的巧妙之处就在于:重新计算后的buckets数组元素保存了“落入”当前桶和“落入”前面所有桶中元素的总数目,而且定义的桶本身就是从大到小且相差为 1 排列的。这样就可以得到一个结论:每个新的buckets数组元素的中它应该小于,等于“落入”当前桶中元素的个数。也就是说,“落入”当前桶中的元素在有序序列中应该排在新buckets数组元素值所确定的位置。

就那上面的新buckets来讲:

元素值为  0 时:此时桶内的元素个数为 0 ,也就是说“落入”当前桶的元素加上“落入”当前桶前面的桶的元素个数总数为 0 ,说明“落入”前面桶元素个数为 0,“落入”当前桶元素的个数也为 0 。为 0 说明什么,说明没有啊。也就是说元素0没有,数组中没有 0 这个枚举。

元素值为 1 时:此时桶内的元素个数为 1,也就是说此时只有它本身,不是吗?所有它排第。

元素值为 2 时:此时桶内的元素个数为 2,也就是说除了他本身,前面还有一个元素,那此时它排第2。

元素值为 3 时:此时桶内的元素个数为 2,也就是说除了他本身,前面还有一个元素,那此时它排第2。不对啊,前面不是元素值2排在第二位么?那它也排第二?

显然这里 3 > 2(元素值大于元素落入当前桶的个数跟落入当前桶前面桶的个数和); 不满足  每个新的buckets数组元素的中它应该小于,等于“落入”当前桶中元素的个数这句话。

……

下面程序实现了桶式排序:

public class BucketsSort {
	/**
	 * 桶式排序
	 * @param data : 待排数组
	 * @param min	:待排数组中最小值
	 * @param max	:待排数组中最大值 +1
	 * 
	 * @see data.length <= (max - min)
	 */
	public static void bucketSort(DataWrap[] data, int min, int max){
		System.out.println( "-开始排序-");
		int arrayLength = data.length;
		
		DataWrap[] tempArr = new DataWrap[arrayLength];
		
		//buckets数组相当于定义了max - min个桶
		//buckets数组用于记录待排序元素的信息
		//max 是序列数组中 (最大值+1)
		int[] buckets = new int[max - min];
		 //计算序列数组中各个元素出现的次数
		for(int i = 0; i < arrayLength; i ++){
			buckets[ data[i].data - min] ++;
		}
		
		System.out.println( Arrays.toString(buckets));

		//将buckets数组里面的每一项等于前面一项和当前项的和
		//也是将data数组中每一数据项应该放的位置存入buckets中
		//也就是说当下面的这个for循环执行完成后buckets数组中放的是索引值放入序列数组中的最终位置
		for(int j = 1; j < max - min;  j ++){
			buckets[j] = buckets[j] + buckets[j - 1];
		}
		
		System.out.println( Arrays.toString(buckets));
		
		
		System.arraycopy(data, 0, tempArr, 0, arrayLength);
		
		//将data数组中的数组放在最终位置的临时数组中
		for(int k = arrayLength - 1; k >= 0; k --){
			data[ --buckets[ tempArr[k].data - min ] ] = tempArr[k];
		}
		
		
	}
	
	public static void main(String[] args){
		DataWrap[] data = {new DataWrap(9,""),
				new DataWrap(5,"*"),
				new DataWrap(-2,""),
				new DataWrap(-2,"*"),
				new DataWrap(-3,""),
				new DataWrap(8,""),
				new DataWrap(5,""),
				new DataWrap(7,""),
				new DataWrap(3,"*"),
				new DataWrap(3,""),
				new DataWrap(1,"")};
		System.out.println( "-排序前-"+Arrays.toString(data));
		
		bucketSort(data, -3, 9+1);
		
		System.out.println( "-排序后-"+Arrays.toString(data));
	}
}


运行结果为:


桶式排序是一种非常优秀的排序算法,时间效率极高,它只需要进行两轮遍历。

桶式排序的空间开销比较大,从上面的实现 程序来看,它需要一个buckets数组来存放元素最终的存放位置和tempArray这样一个数组来临时存放待排序数组。

桶式排序从上面的输出结果来看是稳定的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值