基数排序中关于小桶数据读入详细图解

桶排序:空间换时间的典型代表

背景:最近在学习排序算法时,听韩顺平老师的课发现,往小桶放数据的那段代码搞不清楚,本着求真务实的态度去debug了一下(其实就是脑袋转不过来弯儿),才突然悟了,下面把出现问题的地方和之后的桶排序流程拿出来分析一下,在提供思路参考的同时,顺便当作一个教训,好好吸取。

问题:

当时想不透的地方主要是第一轮排序中的下面这段代码:

	for(int i = 0 ; i<arr.length;i++) {
		int digit = arr[i] % 10;
		bucket[digit][bucketelementcount[digit]]=arr[i];
		bucketelementcount[digit]++;
	}

在这段代码中,始终搞不懂两个地方
        1.二维数组bucket的列中不是存放着arr[]数组中的数据,它怎么能够代表存放到二维数组bucket的对应下标的数值的位数
        2.为什么二维数组中的列中数据要加1,这个也没法表示这个桶中数的个数

解决图解:

当时按着这个第一轮排序的代码debug了一下,发现我太天真了,具体结果如下图:
这里是出问题的点
上面图片最左边的是一维数组bucketeelementcount最终存放的结果,小桶号就是二维数组的行,横放小桶其实可以看成小桶横放在地面上,再依次摞起来
回过头来看问题:可以发现应该是数学的函数没学好,自变量与函数分不清
        对于问题一:二维数组bucket的列中的一维数组初始时的默认值为0,即bucketelementcount[digit]的值无论刚开始传入的digit是啥,bucketelementcount[digit]总是等于0。
        对于第二个问题也就是说这里并不是将原数组中的数据传进来,而是统计出小桶里有的个数。这个统计出来的个数在后面取出小桶数据时就派上用场了。

完整代码(含有详细注释):

提示:可以先看一下第一轮的遍历方式,或者再看一轮遍历方式,最后归纳出整个遍历过程。

//测试
	public static void main(String[] args) {
		int[] arr = {53,3,542,748,14,214};
//		radixsortfirst(arr);
		radixsort(arr);
	}
	
	/**
	 * 先以第一次排序为引入,后再写总的排序方法
	 * 下面第一轮排序radixsortfirst,最后总排序为radixsort
	 * @param arr
	 */
	public static void radixsortfirst(int[] arr) {
		//有一个二维数组存放每次存储的数据。
		int[][] bucket = new int[10][arr.length];
		//定义一个一维数组来表示每个小桶里的存放的值的个数
		int[] bucketelementcount = new int[10];
		//先从个位进行遍历放入
		for(int i = 0 ; i<arr.length;i++) {
			int digit = arr[i] % 10;
			bucket[digit][bucketelementcount[digit]]=arr[i];//这里bucketelementcount[digit]可以看作计数
			bucketelementcount[digit]++;
		}
		//经过上面的遍历,我们能知道,小桶里存放了按个位排序的数值,而一维数组中放了每个小小桶里的数值个数,现在要将排好序的数值放入数组中。
		int index = 0;
		
		for(int i = 0 ; i<bucketelementcount.length;i++) {
			//上面的循环实际上是遍历每个小桶
			if(bucketelementcount[i] != 0) {
			//实际上计数的不为0	
				//下面开始把小桶里的数放回原来的数组中
				for(int j=0;bucketelementcount[i]>j;j++) {
					arr[index++] = bucket[i][j];
				}
			}
		}
		System.out.println(Arrays.toString(arr));
	}
	
	
	public static void radixsort(int[] arr) {
		//确定最大数的位数,因为要按个位、十位、百位...的方式排
		int maxnumber = arr[0];
		for(int i = 0;i<arr.length;i++) {
			if(arr[i]>maxnumber) {
				maxnumber = arr[i];
			}
		}
		//找到最大数后要确定它的位数
		int maxlength = (maxnumber+"").length();
		//接下来开始按位进行排序
		for(int k = 0 ,n = 1; k< maxlength;k++,n *=10) {
		//有一个二维数组存放每次存储的数据。
		int[][] bucket = new int[10][arr.length];
		//定义一个一维数组来表示每个小桶里的存放的值的个数
		int[] bucketelementcount = new int[10];
		//先从个位进行遍历放入
		for(int i = 0 ; i<arr.length;i++) {
			int digit = arr[i] /n % 10;
			//如果按照十位进行排序,要改为arr[i]/10%10;如果按照百位来进行排序arr[i]/100%10;所以直接用arr[i] / Math.pow(10,i)%10也可以
			bucket[digit][bucketelementcount[digit]]=arr[i];//这里bucketelementcount[digit]可以看作计数
			bucketelementcount[digit]++;
		}
		//经过上面的遍历,我们能知道,小桶里存放了按个位排序的数值,而一维数组中放了每个小小桶里的数值个数,现在要将排好序的数值放入数组中。
		int index = 0;
		
		for(int i = 0 ; i<bucketelementcount.length;i++) {
			//上面的循环实际上是遍历每个小桶
			if(bucketelementcount[i] != 0) {
			//实际上计数的不为0	
				//下面开始把小桶里的数放回原来的数组中
				for(int j=0;bucketelementcount[i]>j;j++) {
					arr[index++] = bucket[i][j];
				}
			}
			//每次找完后就置为0,为下一轮排序准备
			bucketelementcount[i]=0;
		}
//		把每次输出改为最后统一输出
//		System.out.println(Arrays.toString(arr));
	}
		System.out.println(Arrays.toString(arr));
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值