java 桶排序

桶排序

桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后依次把各个桶中的记录列出来记得到有序序列。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是比较排序,他不受到O(n log n)下限的影响。
在这里插入图片描述
可以看到我们把相应的元素放入相应的桶里面了.这个放入的规则是这样的:桶是从大到小排列的,并且每一个桶都会有一个数据范围,意思就是0号桶存放是1~ 2数据范围的数据,1号桶存放3~4数据范围的数据,2号桶存放吧5 ~6数据范围内的数据.详细的放入规则我会在下面的实现步骤里面说.这里大家先简单了解一下.

这里大家要注意的一点就是,我们在把元素放入各自相应的桶里面的时候,是需要对桶内的序列进行排序的,意思就是等到每个元素都放入相应的桶里面之后,桶里面相应的序列本身也已经有序了.就如下图所示:

可以看到上面,每个桶内的序列都已经排好序了,那么很显然我们最后就只需要按照桶的序号大小将桶内的元素打印出来,那么我们的序列就已经排好序了.

说完桶排序的基本思想之后,我们接下来就说一下桶排序在代码上是如何实现的,大致有下面这几步:

  • 1.我们首先需要第一次遍历我们的序列,得到我们序列中的最大值MAX以及序列中的最小值MIN,找到我们序列中的最大值与最小值之后,那么我们就可以确定序列中的所有都是在MIN~MAX这个数据范围区间之中.

  • 2.第二步我们就是需要根据序列的数据范围来确定我们到底需要几个桶来存放我们的元素,这一步其实是比较关键的,因为桶的数量太多或者太少都会降低桶排序的效率.

我们举两个例子:

假设我们桶的数量太少,就比如说只有一个桶:
在这里插入图片描述
那么很显然我们的桶排序就又重新退化成我们前两篇内容里介绍的比较算法了.

又假设我们桶的数量太多,就比如说有MAX-MIN+1个桶:
在这里插入图片描述
那么很显然这时候的桶排序又重新退化成了我们上面刚刚讲解过的计数排序了.

所以说我们需要确定好一个适中的桶的数量,不然回就会出现我们上面所说到的几种情况.但是有没有一个特定的公式来确定桶的数量.所以我们还是只能自己确定桶的数量.但是有一个规则我们还是可以考虑进去的,那就是最好让元素平均的分散到每一个桶里.

3.确定完桶的数量之后,我们就可以给每个桶来划分数据范围了.一般是这样划分的,(MAX-MIN+1)/桶的数量,得到的结果就是桶长.之后每个桶的数据范围就通过桶的编号以及桶长就可以确定每个桶的数据范围.就如下面的公式:

左闭右开
桶的数据范围=[MIN+(桶的编号-1)*桶长,MIN+桶的编号 *桶长)
有了每个桶的数据范围时候,我们第二次遍历序列将每个元素存到相应的桶里面了.这个过程我们要注意,在往桶里面添加元素的时候,就需要在每个桶里面将元素排好序.

4.当我们第二次遍历结束之后,我们就只需要按照桶的编号,在将该编号的桶里面的元素打印出来,桶排序就已经完成了.

接下来我们还是通过下面的图来动态演示一下桶排序的过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
了解完桶排序的基本思想之后,按照惯例我们还是来简单分析一下他的一些特点:

  • 桶排序是稳定的,原因和上面计数排序的理由是一样的.

  • 桶排序也是一个通过空间换取时间的算法,但是他的空间复杂度是可以控制的.就像我们上面说的主要就是控制桶的数量.如果桶的数量设置的合理,既能降低时间复杂度,也能降低空间复杂度.
    在这里插入图片描述
    示例代码

//在链表中添加元素的同时需要进行元素的排序
	public static void sort(ArrayList<Integer>list,int i) {
		if(list==null)
			list.add(i);
		//这里采用的排序方式为插入排序
		else {
			int flag=list.size()-1;
			while(flag>=0&&list.get(flag)>i) {
				if(flag+1>=list.size())
					list.add(list.get(flag));
				else  
					list.set(flag+1, list.get(flag));
				flag--;
			}
			if(flag != (list.size()-1))
				//注意这里是flag+1,自己可以尝试将这里换成flag看看,会出现数组越界的情况
			    list.set(flag+1, i);
			else
				list.add(i);
		}
	}
	public static void Bucketsort(int []num,int sum) {
       //遍历得到数组中的最大值与最小值
		int min=Integer.MAX_VALUE;
		int max=Integer.MIN_VALUE;
		for(int i=0;i<num.length;i++) {
			min = min <= num[i] ? min: num[i];
	        max = max >= num[i] ? max: num[i];
		}
		//求出每个桶的长度,这里必须使用Double
		int gap=Math.max((max-min)/(num.length-1),1); 
		ArrayList<Integer>list[]=new ArrayList[sum];
		for(int i=0;i<sum;i++) {
			list[i]=new ArrayList<Integer>();
		}
		//将每个元素放入对应的桶之中同时进行桶内元素的排序
		for(int i=0;i<num.length;i++) {
			System.out.println("元素:"+String.format("%-2s", num[i])+", 被分配到"+(int)Math.floor((num[i]-min)/gap)+"号桶");
			sort(list[(int)Math.floor((num[i]-min)/gap)], num[i]);
		}
		System.out.println();
		for(int i=0;i<sum;i++) {
			System.out.println(String.format("%-1s", i)+"号桶内排序:"+list[i]);
		}
		System.out.println();
		//顺序遍历各个桶,得出我们 已经排序号的序列
		for(int i=0;i<list.length;i++) {
			if(list[i]!=null){
				for(int j=0;j<list[i].size();j++) {
					System.out.print(list[i].get(j)+" ");
				}
			}
		}
		System.out.println();
		System.out.println();
	}
	public static void main(String[] args) {
		
		int []num ={7,4,9,3,2,1,8,6,5,10};
		long startTime=System.currentTimeMillis();
		//这里桶的数量可以你自己定义,这里我就定义成了3
		Bucketsort(num, 3);
		long endTime=System.currentTimeMillis(); 
		System.out.println("程序运行时间: "+(endTime-startTime)+"ms"); 
	}
import java.util.ArrayList;
 
public class BucketSort {
 
	public static void main(String[] args) {
 
		int[] arr = { 1, 45, 32, 23, 22, 31, 47, 24, 4, 15 };
		bucketsort(arr);
 
	}
 
	public static void bucketsort(int[] arr) {
		ArrayList bucket[] = new ArrayList[5];// 声明五个桶
		for (int i = 0; i < bucket.length; i++) {
			bucket[i] = new ArrayList<Integer>();// 确定桶的格式为ArrayList
		}
		for (int i = 0; i < arr.length; i++) {
			int index = arr[i] / 10;// 确定元素存放的桶号
			bucket[index].add(arr[i]);// 将元素存入对应的桶中
		}
		for (int i = 0; i < bucket.length; i++) {// 遍历每一个桶
			bucket[i].sort(null);// 对每一个桶排序
			for (int i1 = 0; i1 < bucket[i].size(); i1++) {// 遍历桶中的元素并输出
				System.out.print(bucket[i].get(i1) + " ");
			}
		}
	}
 
}
————————————————
版权声明:本文为CSDN博主「s逐梦少年」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_52253798/article/details/122970542

上面两种代码,第一个是在每个元素加入桶时都进行一次排序,第二个是将所有元素都加入桶中之后在一起排序,我不知道时间复杂度有没有变化?有没有大佬解惑?

复杂度分析:

理解完桶排序的基本思想之后,我们就需要来分析一下他的时间复杂度,空间复杂度.

  • 时间复杂度

桶排序的时间复杂度和上面的计数排序是一样的,同样也是线性级别的,但是也是增加了桶的时间,所以也是O(n+k)

  • 空间复杂度

上面我们已经说过了,桶排序本身也是一个通过空间来换取时间的算法,所以很明显他的空间复杂度就会很高.并且这个空间复杂度主要就取决于桶的数量以及桶的范围,所以假设有k个桶的话,那么空间复杂度就为O(n+k)


版权声明:本文为CSDN博主「萌萌哒的瓤瓤」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lovely__RR/article/details/112867458

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值