Java 基数排序

基数排序

算法思想:

基数排序的实现步骤非常好理解,但是想要真正理解他的算法思想就稍微有点难度了.那么接下来就来讲解基数排序的算法思想.

首先基数排序是根据数位来进行排序的.他是从个位开始,然后按照每一位的数进行排序,如下图所示:
在这里插入图片描述

排完序之后就往前进一位,然后再将所有的数按照这一位所在的数进行排序,如下图所示:
在这里插入图片描述

重复这个过程直到所有的位数都已经被排过序了.如下图所示:
在这里插入图片描述

并且如果这个过程中碰到某个数在这个为上没有数的话就进行补零操作,将该位看成是0.就比方下图我用红框圈出来的部分:
在这里插入图片描述

等到所有的位数都已经排序完毕之后,我们就可以看到我们已经排序好的序列了.

这个过程相信大家肯定都很好理解,但是相信大家如果是第一次看这个算法的肯定会有和我当初一样的困惑,那就是为什么基数排序选择的是从低位到高位来进行排序的呢,而不是像我们平常比较数据的大小一样,从高位到低位来比较呢?

这里呢我们先不讲为什么,我们先看下面这两个案例:

  • 从高位到低位进行比较
    在这里插入图片描述

  • 从低位到高位进行比较

在这里插入图片描述

对比看了上面两个例子之后相信大家就知道了,很明显我们看到如果是从该我到低位来进行比较的话,我们会发现比较到最后之后序列仍然是无序的,但是从低位到高位进行比较的话,我们就会发现序列到最后已经排好序了.

是不是很奇怪,同样的执行过程,只不过执行的顺序发生了改变,为什么结果就回产生这样的结果呢?产生这个差异的重点就是在我们忽略了一个问题,那就是我们在进行高位到低位比较的时候,高位的权重是高于低位的.就比方下图所示:
在这里插入图片描述

正是因为这个原因,所以我们采取的是从低位到高位比较的过程.

说完基本思想之后,我们来说一下算法的实现步骤:

1.我们第一次遍历序列.找出序列中的最大值MAX,找到MAX之后我们可以确定我们需要比较多少数位了.

2.这时候我们就需要按照元素在该位数对应的数字将元素存入到相应的容器之中.如下图所示:
在这里插入图片描述

3.之后我们再按照容器的顺序将元素重新弹出构成我们接下来需要排序的序列,如下图所示:
在这里插入图片描述

这个从容器弹出的过程需要注意一点,那就是遵循先进先出的原则,所以这个容器选择队列或者是链表比较合适,不能选择栈,因为栈是先进后出,拿取元素的时候回非常麻烦.

4.最后只需要重复2,3步骤,直到最高位也比较完毕,那么整个基数排序就已经完成了.

接下来我们还是通过下面的图来动态演示一下基数排序的过程:
在这里插入图片描述

在了解完基数排序的基本思想之后,按照惯例我们还是来简单分析一下基数排序的特点:

基数排序是稳定的,原因和桶排序以及计数排序的原因一样.
算法图解:
在这里插入图片描述

示例代码:

//将所有的数组合并成原来的数组
	public static void merge(ArrayList<Integer> list[],int num[]) {
		int k=0;
		for(int i=0;i<list.length;i++) {
			if(list[i]!=null) {
				for(int j=0;j<list[i].size();j++) {
					num[k++]=list[i].get(j);
					System.out.print(num[k-1]+" ");
				}
			}
			//合并完成之后需要将链表清空,否则元素会越来越多
			list[i].clear();
		}
		System.out.println();
	}
	//将所有的元素分散到各个链表之中
	public static void split(ArrayList<Integer> list[],int num[],int k) {
		for(int j=0;j<num.length;j++) {
			list[num[j]/k%10].add(num[j]);
		}
		System.out.println("-----------------------------------------------------------------------");
		System.out.println("个位开始数,第"+(String.valueOf(k).length())+"位排序结果:");
		for(int j=0;j<10;j++) {
			System.out.println((String.valueOf(k).length())+"号位,数值为"+j+"的链表结果:"+list[j]);
		}
	}
	public static void main(String[] args) {
		ArrayList<Integer>list[]=new ArrayList [10];
		for(int i=0;i<10;i++) {
			list[i]=new ArrayList<Integer>();
		}
		int []num ={7,14,9,333,201,1,88,6,57,10,56,74,36,234,456};
		long startTime=System.currentTimeMillis();  
		int max=Integer.MIN_VALUE;
		//第一次遍历获得序列中的最大值
		for(int i=0;i<num.length;i++) {
			if(num[i]>max)
				max=num[i];
		}
		int k=1;
		for(int i=0;i<String.valueOf(max).length();i++) {
			split(list, num, k);
			System.out.println("第"+(i+1)+"次排序");
			merge(list, num);
			k=k*10;
		}
		long endTime=System.currentTimeMillis(); 
		System.out.println("程序运行时间: "+(endTime-startTime)+"ms"); 
	}

复杂度分析:

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

  • 时间复杂度

看完我们上面的动图演示之后我们可以看到基数排序只需要根据最大元素的位数,遍历相应次数的序列即可,所以我们可以确定基数排序的时间复杂度一定是线性级别的,但是虽然是线性级别的,但是有一个系数的,这个系数就是最大元素的位数K,所以时间复杂度应该是O(n*k)

  • 空间复杂度

空间复杂度我们也可以看出来,主要就是取决于链表的数量以及序列元素的数量,所以空间复杂度为O(n+k)
————————————————
版权声明:本文为CSDN博主「萌萌哒的瓤瓤」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lovely__RR/article/details/112867458

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于 Java 基数排序,我可以给你一些简单的介绍。 Java 基数排序是一种非比较排序算法,它通过将待排序元素按照位数切割成不同的数字,然后按照每个位数分别比较。具体来说,它将所有待比较数值统一为同样的数位长度,数位较短的数前面补零,然后从最低位开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成后,数列就变成一个有序序列。 Java 基数排序的时间复杂度为 O(d(n+r)),其中 d 是数字位数,n 是待排序元素个数,r 是基数。虽然时间复杂度比较高,但是它的空间复杂度比较低,是一种稳定的排序算法。 下面是 Java 基数排序的代码实现: ``` public static void radixSort(int[] arr) { if (arr == null || arr.length < 2) { return; } int max = Integer.MIN_VALUE; for (int i = 0; i < arr.length; i++) { max = Math.max(max, arr[i]); } int maxDigit = 0; while (max != 0) { max /= 10; maxDigit++; } int mod = 10, div = 1; List<List<Integer>> bucketList = new ArrayList<>(); for (int i = 0; i < 10; i++) { bucketList.add(new ArrayList<>()); } for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) { for (int j = 0; j < arr.length; j++) { int num = (arr[j] % mod) / div; bucketList.get(num).add(arr[j]); } int index = 0; for (int j = 0; j < bucketList.size(); j++) { List<Integer> bucket = bucketList.get(j); for (int k = 0; k < bucket.size(); k++) { arr[index++] = bucket.get(k); } bucket.clear(); } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值