常用的排序算法之基数排序(Radix Sort)
基数排序(Radix Sort)起源或原理
基数排序(Radix Sort)是非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。它按照从低位到高位(或者从高位到低位)依次对待排序的元素进行排序,直到所有的位数都被排序完毕。基数排序的思想借鉴了人类的计数排序法,即按照十进制数的每一位数来分别进行排序。
定义
基数排序(Radix Sort)是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以是稳定的。
引伸义
基数排序可以看作是一种“分配-收集”的排序过程,它按照数字的每一位进行排序,并通过多次分配和收集来完成整个排序过程。基数排序的思想可以扩展到其他非整数的排序场景,比如字符串的字典序排序等。
优缺点
优点:
- 适用于非负整数,且时间复杂度为O(d(n+k)),其中d为数字的位数,n为待排序元素个数,k为数字取值范围。
- 基数排序是稳定的排序算法。
缺点:
- 不适用于负数排序。
- 当待排序元素不是整数时,需要将其转换为整数或字符串才能使用基数排序。
- 对于数据分布不均匀的情况,基数排序可能不是最优选择。
使用场景
基数排序适用于待排序数据为整数,且整数的位数相差不大的情况。在实际应用中,基数排序经常用于对字符串的字典序排序,比如文件名排序、学号排序等。
使用数据一步步举例
假设有一组待排序的非负整数:[170, 45, 75, 90, 802, 24, 2, 66]
。
- 按个位排序:
- 分配:
[2, 24, 45, 66, 75, 90, 170, 802]
- 收集:[2, 24, 45, 66, 75, 90, 170, 802](已经是按个位排序)
- 分配:
- 按十位排序:
- 分配(使用稳定排序):
- 0位桶:[2, 24, 90, 802]
- 5位桶:[45]
- 6位桶:[66]
- 7位桶:[75]
- 1位桶:[170]
- 收集:[2, 24, 45, 66, 75, 90, 170, 802](已经是按十位排序)
- 分配(使用稳定排序):
- 按百位排序(由于这组数中只有802有百位,所以这一步实际上只影响802的位置):
- 分配(使用稳定排序):
- 0位桶:[2, 24, 45, 66, 75, 90, 170]
- 8位桶:[802]
- 收集:[2, 24, 45, 66, 75, 90, 170, 802](已经是按百位排序,即完全排序)
- 分配(使用稳定排序):
Java示例代码
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 | public class RadixSort { // 基数排序的主方法 public static void radixSort( int [] arr) { if (arr == null || arr.length <= 1 ) { return ; } // 获取数组中最大数的位数 int maxDigit = getMaxDigit(arr); // 从最低位开始排序 for ( int digit = 1 ; digit <= maxDigit; digit++) { // 调用计数排序对指定位进行排序 countingSort(arr, digit); } } // 获取数组中最大数的位数 private static int getMaxDigit( int [] arr) { int max = arr[ 0 ]; for ( int num : arr) { if (num > max) { max = num; } } int digit = 0 ; while (max > 0 ) { max /= 10 ; digit++; } return digit; } // 计数排序方法,用于基数排序中的每一位 private static void countingSort( int [] arr, int digit) { int maxVal = getMaxValue(arr, digit); // 获取当前位的最大值 int [] output = new int [arr.length]; // 临时数组,用于存储排序后的结果 int [] count = new int [maxVal + 1 ]; // 计数数组 // 初始化计数数组 for ( int i = 0 ; i <= maxVal; i++) { count[i] = 0 ; } // 计算每个元素在当前位上的出现次数 for ( int i = 0 ; i < arr.length; i++) { int index = getDigit(arr[i], digit); count[index]++; } // 修改计数数组,变为前缀和 for ( int i = 1 ; i <= maxVal; i++) { count[i] += count[i - 1 ]; } // 从后向前遍历,将元素放到正确的位置上 for ( int i = arr.length - 1 ; i >= 0 ; i--) { int index = getDigit(arr[i], digit); output[count[index] - 1 ] = arr[i]; count[index]--; } // 将排序后的元素复制回原数组 System.arraycopy(output, 0 , arr, 0 , arr.length); } // 获取指定位置上的数字(0-based index) private static int getDigit( int num, int digit) { return (num / ( int )Math.pow( 10 , digit - 1 )) % 10 ; } // 获取数组中在当前位上的最大值 private static int getMaxValue( int [] arr, int digit) { int maxVal = 0 ; for ( int num : arr) { int digitVal = getDigit(num, digit); if (digitVal > maxVal) { maxVal = digitVal; } } return maxVal; } // 测试方法 public static void main(String[] args) { int [] arr = { 170 , 45 , 75 , 90 , 802 , 24 , 2 , 66 }; radixSort(arr); for ( int num : arr) { System.out.print(num + " " ); } } } |
这个完整的代码示例包括基数排序的主方法radixSort
,辅助方法getMaxDigit
来获取最大数的位数,countingSort
来实现计数排序以在每个位上进行排序,getDigit
来获取指定位置上的数字,以及getMaxValue
来获取数组中在当前位上的最大值。最后,main
方法用于测试基数排序算法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix