桶排序
一---导读
我们先思考这样一个数学问题,如何取出一个数的个位,十位,百位。。。?
以128为例,要取出个位8我们可以对其进行直接取余10操作 128 % 10 = 8,取出十位2我们可以先对其除以10再取余10。
128 % 10 = 12,12 % 10 = 2;
二---桶排算法思路图解
假设现在有数组arr{3, 15, 122, 64}
我们对其用桶排进行排序步骤如下:
第一轮:对个位进行排序
第二轮:对十位进行排序
第三轮:对百位进行排序
通过以上的图片我们可以看出,只要排三次,也就是到最高位百位,即可得出想要的结果。
注:基数排序其实就是桶排序的精简版本
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | 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) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~