文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基数排序的1个小技巧,2种排序方式,3种排序算法

2024-12-14 01:01

关注

概念

基数排序是非比较型整数排序算法,其原理是将整数按位分割进行排序。基数排序适用于大范围数据排序,打破了计数排序的限制。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

2种排序方式

最低位优先法(LSD):从最低位向最高位依次按位进行排序。

最高位优先法(MSD):从最高位向最低位依次按位进行排序。

按位分割小技巧

arr[i] / digit % 10,其中digit为10^n。

LSD排序算法实现

算法思想

按位进行计数排序

算法实现代码

  1.  
  2. private static int[] countingSort(int[] arr, int divid){ 
  3.  
  4.     int[] bucket = new int[10]; 
  5.     for (int i = 0; i < arr.length; i++) { 
  6.         bucket[arr[i] / divid % 10]++; 
  7.     } 
  8.  
  9.     for (int i = 1; i < bucket.length; i++) { 
  10.         bucket[i] = bucket[i-1] + bucket[i]; 
  11.     } 
  12.  
  13.     int[] sortArr = new int[arr.length]; 
  14.     for (int i = arr.length - 1; i >= 0; i--){ 
  15.         int position = bucket[arr[i] / divid % 10]; 
  16.         sortArr[position - 1] = arr[i]; 
  17.         bucket[arr[i] / divid % 10]--; 
  18.     } 
  19.     return sortArr; 
  20.  
  21. public static int[] radixSort(int[] arr) { 
  22.     // 查找数组最大值 
  23.     int max = arr[0]; 
  24.     for (int i = 0; i < arr.length; i++) { 
  25.         max = Math.max(arr[i], max); 
  26.     } 
  27.     // 按位排序 
  28.     int digit = 1; 
  29.     for (int i = 1; i < max; digit*=10, i = digit) { 
  30.         arr = countingSort(arr, digit); 
  31.     } 
  32.     return arr; 

排序验证:

  1. public static void main(String[] args) { 
  2.      int[] arr = {999,1000,1001,1000,999,1005}; 
  3.      System.out.println("排序前:" + JSON.toJSONString(arr)); 
  4.      int[] sortArr = radixSort(arr); 
  5.      System.out.println("排序后:" + JSON.toJSONString(sortArr)); 
  6.  } 

排序前:[999,1000,1001,1000,999,1005] 排序后:[999,999,1000,1000,1001,1005]

MSD排序算法实现

算法思想

从最高位开始,按位分组,当组内元素个数>1时,递归下一位分组,一直分到个位结束;收集元素个数=1的。

算法步骤

比如,对数组[333,1002,1001,1000,333,1003,2000]进行排序,操作步骤如下:

算法实现代码

  1. public static int[] sort(int[] arr){ 
  2.  
  3.     int max = arr[0]; 
  4.     for (int i = 0; i < arr.length; i++) { 
  5.         // 获取最大值 
  6.         max = Math.max(arr[i], max); 
  7.     } 
  8.  
  9.     // 获取最大值的位数 
  10.     int digit = getDataDigit(max); 
  11.     // 计算最大值的基数 
  12.     int radix = new Double(Math.pow(10, digit - 1)).intValue(); 
  13.     // msd基数排序 
  14.     return msdSort(arr, radix); 
  15.  
  16.  
  17. public static int[] msdSort(int[] arr, int radix){ 
  18.  
  19.     // 递归分组到个位,退出 
  20.     if (radix <= 0) { 
  21.         return arr; 
  22.     } 
  23.  
  24.     // 分组计数器 
  25.     int[] groupCounter = new int[10]; 
  26.     // 分组桶 
  27.     int[][] groupBucket = new int[10][arr.length]; 
  28.     // 遍历待排序数组,按位分组 
  29.     for (int i = 0; i < arr.length; i++) { 
  30.         // 计算分组桶位置 
  31.         int position = arr[i] / radix % 10; 
  32.         // 将元素存入分组 
  33.         groupBucket[position][groupCounter[position]] = arr[i]; 
  34.         // 当前分组计数加1 
  35.         groupCounter[position]++; 
  36.     } 
  37.  
  38.     int index = 0; 
  39.     int[] sortArr = new int[arr.length]; 
  40.  
  41.     // 遍历分组计数器 
  42.     for (int i = 0; i < groupCounter.length; i++) { 
  43.         // 组内元素数量>1,递归分组 
  44.         if (groupCounter[i] > 1) { 
  45.             int[] copyArr = Arrays.copyOf(groupBucket[i], groupCounter[i]); 
  46.             // 递归分组 
  47.             int[] tmp = msdSort(copyArr, radix / 10); 
  48.             // 收集递归分组后的元素 
  49.             for (int j = 0; j < tmp.length; j++) { 
  50.                 sortArr[index++] = tmp[j]; 
  51.             } 
  52.         } else if (groupCounter[i] == 1) { 
  53.             // 收集组内元素数量=1的元素 
  54.             sortArr[index++] = groupBucket[i][0]; 
  55.         } 
  56.     } 
  57.  
  58.     return sortArr; 
  59.  
  60.  
  61. public static int getDataDigit(int data) { 
  62.     //        int index = 0; 
  63.     //        int digit = 1; 
  64.     //        while (data / digit >0) { 
  65.     //            digit *= 10; 
  66.     //            index++; 
  67.     //        } 
  68.     //        return index
  69.  
  70.     return String.valueOf(data).length(); 

验证排序结果:

  1. public static void main(String[] args) { 
  2.     int[] arr = {333,1002,1001,1000,333,1003,2000}; 
  3.     System.out.println("排序前:" + JSON.toJSONString(arr)); 
  4.     int[] sortArr = sort(arr); 
  5.     System.out.println("排序后:" + JSON.toJSONString(sortArr)); 

排序前:[333,1002,1001,1000,333,1003,2000] 排序后:[333,333,1000,1001,1002,1003,2000]

三向切分字符快速排序

算法思想

按位将字符串切分为三个区间,小于v区间:[lo,lt-1],等于v区间:[lt,gt],大于v区间: [gt+1,hi],依次递归三个区间。

算法步骤

算法实现代码

  1.  
  2. public static void sortStr(String[] arr, int lo, int hi, int d){ 
  3.     if (hi <= lo) { 
  4.         return
  5.     } 
  6.     // 定义小于v的看门lt, 大于v的看门gt 
  7.     int lt = lo, gt = hi, i = lo + 1, v = charAt(arr[lo],d); 
  8.     while (i <= gt){ 
  9.         int t = charAt(arr[i], d); 
  10.         if (t < v) { 
  11.             exch(arr, i++, lt++); 
  12.         } else if (t > v) { 
  13.             exch(arr, i, gt--); 
  14.         } else { 
  15.             i++; 
  16.         } 
  17.     } 
  18.  
  19.     // 递归小于v的区间 
  20.     sortStr(arr, lo, lt - 1, d); 
  21.     // 递归等于v的区间 
  22.     if (v >= 0) { 
  23.         sortStr(arr, lt, gt, d + 1); 
  24.     } 
  25.     // 递归大于v的区间 
  26.     sortStr(arr, gt + 1, hi, d); 
  27. private static int charAt(String s, int d) { 
  28.     if (d < s.length()) { 
  29.         return s.charAt(d); 
  30.     } 
  31.     return -1; 
  32. public static void exch(String[] arr, int sourceIdx, int targetIdx) { 
  33.     String tmp = arr[sourceIdx]; 
  34.     arr[sourceIdx] = arr[targetIdx]; 
  35.     arr[targetIdx] = tmp; 
  36. 结果验证: 
  37.  
  38.  public static void main(String[] args) { 
  39.      String[] a = new String[]{"by","air","she","shell","the","okay","bump","shirt","shells","sh","the","shells","the"}; 
  40.      System.out.println("排序前:" + JSON.toJSONString(a)); 
  41.      sortStr(a, 0, a.length - 1, 0); 
  42.      System.out.println("排序后:" + JSON.toJSONString(a)); 
  43.  } 

排序前:["by","air","she","shell","the","okay","bump","shirt","shells","sh","the","shells","the"] 排序后:["air","bump","by","okay","sh","she","shell","shells","shells","shirt","the","the","the"]

三种排序算法对比

算法

是否稳定

原地排序

运行时间

额外空间

优点领域

低位优先的字符串排序(LSD)

O(n x k)

O(n + k)

较短的定长字符串

高位优先的字符串排序(MSD)

O(n x k)

O(N+kk)

随机字符串

三向字符串快速排序

O(NlogN)

W+logN

通用排序算法,特别适用于含有较长公共前缀的字符串数组

总结

基数排序是稳定、非比较排序,适合用于大数据范围的。

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯