基数排序 RadixSort
今晚看了一篇阅读,跑了会步,闲来无事又看起了严奶奶的数据结构,发现基数排序很有意思,用一种多关键字的思想,在基数较少的情况下可以取得较好的效果。
书中的讲解通俗易懂(但是严奶奶的代码我是看不懂的),我一下子就看懂了。立即打开电脑开始练习。
学习链接:最快最简单的排序——桶排序(超萌的漫画,非常容易理解)、基数排序、排序算法系列:基数排序
今天编的很爽,调试的也很爽。只debug了三次,就没虫了。一个虫比较智障,是我发昏了。还有一个虫是在【定位到链表尾部】这个操作出现了逻辑盲区,一个虫是在【构造基数链表】是没有对先驱节点进行擦屁股操作,导致后期处理死循环。
唯一遗憾的是这个测试代码只能对不含负数的测试数据进行排序,如果包含了负数,radix数组所表示的基数肯定不是0~9了,而是,-9~9,一大堆东西都要改。
Java代码:
1 public class Main { 2 3 public static void main(String[] args) { 4 int []nums={3,2,4,6,7,1,3,11,100,1000,1,20}; 5 RadixSort sort=new RadixSort(nums); 6 System.out.print(sort); 7 } 8 } 9 10 class RadixSort{ 11 int [] sortAns; 12 class LinkedNums{ 13 int num=0; 14 LinkedNums next=null; 15 } 16 LinkedNums first=new LinkedNums(); 17 LinkedNums radix[]=new LinkedNums[10];//0~9 18 public String toString(){ 19 int i; 20 String str=new String(""); 21 for(i=0;i<sortAns.length;i++) str+=String.valueOf(sortAns[i])+" "; 22 str+="\n"; 23 return str; 24 } 25 private void FormLinkedNums(int [] nums){ 26 int i; 27 int len=nums.length; 28 LinkedNums point=first; 29 point.num=nums[0]; 30 for(i=1;i<len;i++){ 31 LinkedNums node=new LinkedNums(); 32 point.next=node; 33 point=point.next; 34 point.num=nums[i]; 35 } 36 } 37 private int GetInNum(int num,int rank){ 38 return 39 (num%((int)Math.pow(10.0, (double)rank)))//运算得到当前取出的数 40 / 41 ((int)Math.pow(10.0, (double)(rank-1))); 42 } 43 private int GetMaxLenInArr(int [] nums){ 44 int i; 45 int max=0; 46 for(i=0;i<nums.length;i++){ 47 int len=String.valueOf(nums[i]).length(); 48 if(len>max) max=len; 49 } 50 return max; 51 } 52 RadixSort(int [] nums){ 53 int i,j; 54 int len=nums.length; 55 for(i=0;i<=9;i++) radix[i]=null;//对radix进行初始化 56 FormLinkedNums(nums); 57 int rank=1;//首先进行x%10的运算,再进行(x%100)/10的运算,再进行(x%1000)/100的运算 58 int cirNum=GetMaxLenInArr(nums); 59 for(j=0;j<cirNum;j++){ 60 LinkedNums point=first; 61 while(point!=null){ 62 int num=GetInNum(point.num,rank); 63 if(radix[num]==null){//基数数组没有勾链 64 radix[num]=point; 65 }else{ 66 LinkedNums local=radix[num]; 67 while(local.next!=null) local=local.next; //【1】 68 local.next=point;//在这里进行勾链是不会破坏程序运行的。因为local的下标比point小。破坏local的后继关系没有影响 69 } 70 LinkedNums pre=point;//【2】 71 point=point.next; 72 pre.next=null; //【2】 73 } 74 //基数数组勾链完毕。重新构造链表。 75 //首先给first赋值。 76 boolean isLinkedFirst=false; 77 point=null; 78 for(i=0;i<=9;i++){ 79 if(radix[i]!=null){ 80 LinkedNums local=radix[i]; 81 if(! isLinkedFirst){ 82 first=local; 83 isLinkedFirst=true; 84 point=first; 85 local=local.next; 86 } 87 while(local!=null){ 88 point.next=local; 89 point=point.next; 90 local=local.next; 91 } 92 } 93 } 94 for(i=0;i<=9;i++) radix[i]=null;//对radix进行初始化 95 rank++;//阶数递增 96 } 97 //将链表写入结果数组。 98 sortAns=new int[len]; 99 i=0; 100 while(first!=null){ 101 sortAns[i++]=first.num; 102 first=first.next; 103 } 104 } 105 }
逻辑盲区总结:
【1】:line 67。将 local.next!=null 写成了 local!=null ,导致空指针错误。
【2】:line 70、72。没有对前驱结点进行擦屁股操作。