基数排序算是桶排序和计数排序的衍生吧,因为基数排序里面会用到这两种其中一种。
基数排序针对的待排序元素是要有高低位之分的,比如单词adobe,activiti,activiti就高于adobe,这个是根据ascll码来的。
现在我们可以提出一个问题,怎样对字典里面的单词进行排序呢?
比如我们现在有如下单词:
"Java", "Mongodb", "Redis", "Kafka", "javascript", "mysql", "mybatis", "kindle",
"rpc", "Algorithm", "mergeSort", "quickSort", "Adobe"
我们要怎么对它排序呢,这里就可以用到基数排序了,基数排序的原理就是我们将一个元素按高低位分成单个个体,比如Adobe我们
就分成A,d,o,b,e,Algorithm我们就分成A,l,g,o,r,i,t,h,m,然后我们从右往左,依次比较即可。
但是这里Adobe和Algorithm并不能直接比较,因为他们的长短不一,所以在比较之前我们应该找到最长的元素的长度,然后将其余短的元素补全
到一样长:
Adobe0000
Algorithm
这样才可以形成比较,从右往左,0:m,0:h,0:t,0:i,e:r,b:o,o:g,d:l,A:A,我们就可以比较出来Adobe > Algorihtm
跟着以下的图片会更清楚原理:
从上图我们可以看出,基数排序会从右往左依次比较(即在我们的程序实现里面需要遍历很多次),而具体要遍历多少次则取决于最长的元素有多长,从右往左对每个位
的元素比较可以用到桶排序或计数排序,桶排序和计数排序的时间复杂度都是O(n),假设最大的元素长度为K,则基数排序的时间复杂度为O(k * n),而k一般不会有多大,
可以视为常量,所以基数排序的时间复杂度也是O(n)。
以下是我的Java实现:
1 package com.structure.sort; 2 3 /** 4 * @author zhangxingrui 5 * @create 2019-01-30 14:58 6 **/ 7 public class RadixSort { 8 9 public static void main(String[] args) { 10 /*int[] numbers = {19, 36, 24, 10, 9, 29, 1, 0, 3, 60, 100, 1001, 999, 520, 123, 96}; 11 radixSort(numbers); 12 for (int number : numbers) { 13 System.out.println(number); 14 }*/ 15 16 String[] words = {"Java", "Mongodb", "Redis", "Kafka", "javascript", "mysql", "mybatis", "kindle", "rpc", "Algorithm", "mergeSort", "quickSort", "Adobe"}; 17 // String[] words = {"Java", "mongodb", "Kafka"}; 18 radixSort(words); 19 for (String word : words) { 20 System.out.println(word.replaceAll("0", "")); 21 } 22 } 23 24 /** 25 * @Author: xingrui 26 * @Description: 基数排序(单词) 27 * @Date: 15:53 2019/1/30 28 */ 29 private static void radixSort(String[] words){ 30 int exp = 0; 31 int maxLength = getMaxLength(words); 32 autoComplete(words, maxLength); 33 for(exp = 1; exp <= maxLength; exp++){ 34 countingSort(words, exp); 35 } 36 } 37 38 /** 39 * @Author: xingrui 40 * @Description: 计数排序(单词) 41 * @Date: 13:57 2019/1/30 42 */ 43 private static void countingSort(String[] words, int exp){ 44 int n = words.length; 45 String[] r = new String[n]; 46 int[] c = new int[122]; 47 48 for(int i = 0; i < n; ++i){ 49 int asc = (byte)words[i].charAt(words[i].length() - exp); 50 c[asc]++; 51 } 52 53 for(int i = 1; i < 122; ++i){ 54 c[i] = c[i-1] + c[i]; 55 } 56 57 for (int i = n - 1; i >= 0; --i){ 58 int asc = (byte)words[i].charAt(words[i].length() - exp); 59 int index = c[asc]; 60 r[index - 1] = words[i]; 61 c[asc]--; 62 } 63 64 for(int i = 0; i < n; ++i){ 65 words[i] = r[i]; 66 } 67 } 68 69 /** 70 * @Author: xingrui 71 * @Description: 基数排序(纯数字) 72 * @Date: 15:00 2019/1/30 73 */ 74 private static void radixSort(int[] numbers){ 75 int exp = 0; 76 int maxNumber = getMaxNumber(numbers); 77 for(exp = 1; maxNumber/exp > 0; exp *= 10){ 78 countingSort(numbers, exp); 79 } 80 } 81 82 /** 83 * @Author: xingrui 84 * @Description: 计数排序(纯数字) 85 * @Date: 13:57 2019/1/30 86 */ 87 private static void countingSort(int[] numbers, int exp){ 88 int n = numbers.length; 89 90 int[] r = new int[n]; 91 int[] c = new int[10]; 92 93 for(int i = 0; i < n; ++i){ 94 c[numbers[i]/exp % 10]++; 95 } 96 97 for(int i = 1; i < 10; ++i){ 98 c[i] = c[i-1] + c[i]; 99 } 100 101 for (int i = n - 1; i >= 0; --i){ 102 int index = c[numbers[i] / exp % 10]; 103 r[index - 1] = numbers[i]; 104 c[numbers[i] / exp % 10]--; 105 } 106 107 for(int i = 0; i < n; ++i){ 108 numbers[i] = r[i]; 109 } 110 } 111 112 /** 113 * @Author: xingrui 114 * @Description: 自动补全单词 115 * @Date: 16:38 2019/1/30 116 */ 117 private static void autoComplete(String[] words, int maxLength){ 118 int i = 0; 119 for (String word : words) { 120 if(word.length() < maxLength){ 121 int value = maxLength - word.length(); 122 StringBuilder sb = new StringBuilder(); 123 for(int j = 0; j < value; ++j){ 124 sb.append("0"); 125 } 126 words[i] = word + sb; 127 } 128 i++; 129 } 130 } 131 132 /** 133 * @Author: xingrui 134 * @Description: 获取字符串最大的长度 135 * @Date: 15:56 2019/1/30 136 */ 137 private static int getMaxLength(String[] words){ 138 int maxLength = words[0].length(); 139 for(int i = 1; i < words.length; ++i){ 140 if(words[i].length() > maxLength) 141 maxLength = words[i].length(); 142 } 143 return maxLength; 144 } 145 146 /** 147 * @Author: xingrui 148 * @Description: 获取最大的数字 149 * @Date: 15:56 2019/1/30 150 */ 151 private static int getMaxNumber(int[] numbers){ 152 int maxNumber = numbers[0]; 153 for(int i = 1; i < numbers.length; ++i){ 154 if(numbers[i] > maxNumber) 155 maxNumber = numbers[i]; 156 } 157 return maxNumber; 158 } 159 160 }
其中需要注意就是在排序之前需要找到最大的元素长度以确定循环次数和根据最大元素长度补全比较短的元素。
程序执行结果:
需要特别说明的是,文中的图片均截图极客网王争老师的专栏《数据结构与算法之美》,如有侵权,请联系我删除。
有需要的朋友也可以去订阅这个专栏,讲的挺不错的,没有视频,只有文字和音频。