桶排序
一---导读
我们先思考这样一个数学问题,如何取出一个数的个位,十位,百位。。。?
以128为例,要取出个位8我们可以对其进行直接取余10操作 128 % 10 = 8,取出十位2我们可以先对其除以10再取余10。
128 % 10 = 12,12 % 10 = 2;
二---桶排算法思路图解
假设现在有数组arr{3, 15, 122, 64}
我们对其用桶排进行排序步骤如下:
第一轮:对个位进行排序
第二轮:对十位进行排序
第三轮:对百位进行排序
通过以上的图片我们可以看出,只要排三次,也就是到最高位百位,即可得出想要的结果。
注:基数排序其实就是桶排序的精简版本
代码实现:
package Sort; import java.util.Arrays; public class RadixSort { public static void main(String[] args) { int[] arr = {3, 15, 122, 64}; System.out.println("排序前" + Arrays.toString(arr)); radixSort(arr); } // 基数排序 public static void radixSort(int[] arr) { // 定义一个二维数组,表示10个桶,每个桶就是一个一维数组 // 说明 // 1 二维数组包含10个一维数组 // 2 为了防止数据溢出,则每个一维数组(桶)的大小为arr.length // 3 很明显基数排序是使用空间换时间的经典算法 int[][] bucket = new int[10][arr.length]; //为了记录每个桶中实际存放了多少个数据,我们定义一个一维数组来记录各个桶每次放入的数据的个数 // 可以这样理解 // bucketElementCount[0],记录的就是bucket[0]桶的放入数据个数,可以看做10个指针(没学过c/c++忽略) // 可以这样理解,bucketElementCounts[0],记录的是bucket[0]桶的放入数据个数。 int[] bucketElementCounts = new int[10]; // 第一轮(针对个位进行排序处理) for (int j = 0; j < arr.length ; j++) { // 取出每个元素的个位 int digitOfElment = arr[j] / 1 % 10; // 放入到对应的桶中,就是刚刚算出来的这个桶 bucket[digitOfElment][bucketElementCounts[digitOfElment]] = arr[j]; bucketElementCounts[digitOfElment]++; } // 按照这个桶的顺序 (一维数组的下标依次取出数据,放入原来数组) int index = 0; // 遍历每一个桶,并将桶中的数据放到原数组 for (int k = 0; k < bucketElementCounts.length ; k++) { // 如果桶中有数据,我们才放入到原数组。 if(bucketElementCounts[k] != 0) { // 循环该桶即第k个桶,即第k个一维数组,放入 for (int l = 0; l < bucketElementCounts[k] ; l++) { // 取出元素放到arr arr[index++] = bucket[k][l]; } } // 第一轮处理后需要将 每个bucketElementCounts[k]=0 bucketElementCounts[k] = 0; } System.out.println("第一轮,对个位的数据的处理" + Arrays.toString(arr)); // 第二轮(针对十位进行排序处理) for (int j = 0; j < arr.length ; j++) { // 取出每个元素的个位 int digitOfElment = arr[j] / 10 % 10; // 放入到对应的桶中,就是刚刚算出来的这个桶 bucket[digitOfElment][bucketElementCounts[digitOfElment]] = arr[j]; bucketElementCounts[digitOfElment]++; } // 按照这个桶的顺序 (一维数组的下标依次取出数据,放入原来数组) index = 0; // 遍历每一个桶,并将桶中的数据放到原数组 for (int k = 0; k < bucketElementCounts.length ; k++) { // 如果桶中有数据,我们才放入到原数组。 // 注意,上一轮结束后我们并没有把桶里的数清零。第二轮再放的话需要重新进行累积,所以会报错Index 6 out of bounds for length 6 if(bucketElementCounts[k] != 0) { // 循环该桶即第k个桶,即第k个一维数组,放入 for (int l = 0; l < bucketElementCounts[k] ; l++) { // 取出元素放到arr arr[index++] = bucket[k][l]; } } bucketElementCounts[k] = 0; } System.out.println("第二轮,对个位的数据的处理" + Arrays.toString(arr)); // 第三轮(针对十位进行排序处理) for (int j = 0; j < arr.length; j++) { // 取出每个元素的个位 int digitOfElment = arr[j] / 100 % 10; // 放入到对应的桶中,就是刚刚算出来的这个桶 bucket[digitOfElment][bucketElementCounts[digitOfElment]] = arr[j]; bucketElementCounts[digitOfElment]++; } // 按照这个桶的顺序 (一维数组的下标依次取出数据,放入原来数组) index = 0; // 遍历每一个桶,并将桶中的数据放到原数组 for (int k = 0; k < bucketElementCounts.length; k++) { // 如果桶中有数据,我们才放入到原数组。 // 注意,上一轮结束后我们并没有把桶里的数清零。第二轮再放的话需要重新进行累积,所以会报错Index 6 out of bounds for length 6 if (bucketElementCounts[k] != 0) { // 循环该桶即第k个桶,即第k个一维数组,放入 for (int l = 0; l < bucketElementCounts[k]; l++) { // 取出元素放到arr arr[index++] = bucket[k][l]; } } } System.out.println("第三轮,对个位的数据的处理" + Arrays.toString(arr)); } }
优化代码:我们发现上面一-三步可以用for循环来包含。
1 package Sort; 2 3 import java.util.Arrays; 4 5 public class RadixSortTest { 6 public static void main(String[] args) { 7 int[] arr = {13, 2, 164, 259}; 8 System.out.println("原数组为:" + Arrays.toString(arr)); 9 RadixSort1(arr); 10 } 11 12 public static void RadixSort1(int[] arr) { 13 // 构造出桶 14 int[][] bucket = new int[10][arr.length]; 15 // 用一个数组来存放每个桶中有多少元素 ,有10个桶就是10个。 16 int[] bucketElementCounts = new int[10]; 17 18 // 第一轮排序 19 // 取出数据的个位23 24 // 获取最大的数的长度 25 int max = arr[0]; // 假设第一个数就是最大的 26 for(int m = 1; m < arr.length; m++) { 27 if(max < arr[m]) { 28 max = arr[m]; 29 } 30 } 31 System.out.println("最大的数为:" + max); 32 // 获取最大数的长度 33 int maxlength = (max + "").length(); // 加空串使其变为字符串,注意空串之间不要打空格,否则长度会加1,可以调用length函数 34 35 36 37 for(int l = 0, n = 1; l < maxlength; l++, n *= 10) { 38 for (int i = 0; i < arr.length; i++) { // 注意这里不是arr.length - 1,要不然最后一位处理不到 39 int digit = arr[i] / n % 10; 40 // 放入对应的桶中 41 bucket[digit][bucketElementCounts[digit]] = arr[i]; 42 // 记录桶数据的数组对应位置加1 43 bucketElementCounts[digit]++; 44 } 45 // 按照当前顺序取出桶中的元素放回数组中 46 int index = 0; 47 for (int j = 0; j < bucket.length; j++) { 48 // 先判断这个桶中是否有元素,有元素的话再循环取出 49 if (bucketElementCounts[j] != 0) { 50 for (int k = 0; k < bucketElementCounts[j]; k++) { 51 arr[index++] = bucket[j][k]; 52 } 53 } 54 bucketElementCounts[j] = 0; 55 56 } 57 count++; 58 System.out.println("第" + count + "轮排序完" + Arrays.toString(arr)); 59 }
}
posted on 2021-03-19 09:26 Love&Share 阅读(46) 评论(0) 编辑 收藏 举报