最近數據結構剛剛講完了基數排序,以下我的一些見解:
大多數的排序都是通過比較數據大小的方法對待排數據序列進行排序整理過程。
而基數排序卻很另類,那么,基數排序是采用怎樣的策略進行排序的呢?
簡要概括一下:基數排序是通過“分配”和“收集”兩個過程來實現排序的。
而這個思想該如何理解呢?請看以下例子:
(1)有以下待排序列
309 385 867 183 341 605 385
(2)第一次分配和收集:
首先按照各個數據的個位數字(即按照9,5,7,3,1,5,5)分配到0-9的10個區間內
結果如下:
分配結束后。接下來將所有空間中的數據按照序號由小到大依次重新收集起來,得到如下仍然無序的數據序列:
(3)第二次分配和收集:
這次按照十位數字進行分配,步驟同上
結果如下:
分配結束后。接下來將所有空間中的數據按照序號由小到大依次再次收集起來,得到如下仍然無序的數據序列:
(4)第三次分配和收集:
這次按照百位數字進行分配,步驟同上
結果如下:
分配結束后。接下來將所有空間中的數據按照序號由小到大依次再次收集起來;
哎?!停一下!奇怪,數據竟然有序了!
當然,數據分別按照個,十,百位依次排序后自然是有序的,至於為什么,我相信細心的讀者已經想明白了。
下面介紹一下對上面所說的基數排序算法做一些補充:
(1)如果數據大小更大,則需按照上面的思路繼續排序(比如排序到千位,萬位.....),排序的次數就是待排數據中最大數字的位數;
(2)上面的分析是說的數字的排序,如果要對等長的字符串集合排序,則各個空間的關鍵字由0-9變為‘a’-‘z’;
(3)基數排序是穩定的,而且看起來似乎在時間代價上很好,但實際並非如此,它在記錄數較關鍵字大得多的情況下比較有效,還有一個缺點是:它對一些數據類型來說是難於實現的,如對實型或不等長的字串。
下面再思考一個問題:既然我們可以從最低位到最高位進行如此的分配收集,那么是否可以由最高位到最低位依次操作呢? 答案是完全可以的。
基於兩種不同的排序順序,我們將基數排序分為LSD(Least significant digital)或MSD(Most significant digital),
LSD的排序方式由數值的最右邊(低位)開始,而MSD則相反,由數值的最左邊(高位)開始。
注意一點:LSD的基數排序適用於位數少的數列,如果位數多的話,使用MSD的效率會比較好。
下面給出算法實現代碼:
鏈式實現:

1 #include <iostream> 2 3 using namespace std; 4 const int maxn=100000+10; 5 const int Radix=20; 6 typedef struct 7 { 8 int next; 9 int key; 10 }SLNode; 11 typedef struct 12 { 13 SLNode r[maxn]; 14 int length; 15 }SLList; 16 typedef int ArrType[Radix]; 17 ArrType f,e; 18 int Ord(int k,int j) 19 { 20 for(int i=1;i<j;i++) 21 k/=10; 22 k%=10; 23 return k+10; 24 } 25 void Print_L(SLList L) 26 { 27 int mrk=0; 28 for(int p=L.r[0].next;p;p=L.r[p].next) 29 { 30 if(mrk) 31 printf(" "); 32 printf("%d",L.r[p].key); 33 mrk=1; 34 } 35 printf("\n"); 36 } 37 void Distribute(SLList &L,int i,ArrType &f,ArrType &e) 38 { 39 //printf("i=%d\n",i); 40 for(int i=0;i<Radix;i++) 41 f[i]=0; 42 //for(int p=L.r[0].next;p!=0;p=L.r[p].next) 43 for(int p=L.r[0].next;p;p=L.r[p].next) 44 { 45 int k=Ord(L.r[p].key,i); 46 //printf("%d\n",k); 47 if(f[k]==0) 48 { 49 f[k]=e[k]=p; 50 } 51 else 52 { 53 L.r[e[k]].next=p; 54 e[k]=p; 55 } 56 } 57 } 58 void Collect(SLList &L,int i,ArrType &f,ArrType &e) 59 { 60 int j=0; 61 while(f[j]==0) 62 j++; 63 L.r[0].next=f[j]; 64 int tail=e[j]; 65 while(j<Radix) 66 { 67 j++; 68 while(j<Radix&&f[j]==0) 69 j++; 70 L.r[tail].next=f[j]; 71 tail=e[j]; 72 } 73 } 74 void RadixSort(SLList &L) 75 { 76 for(int i=1;i<=6;i++)//待排數據中最大值的位數,可根據實際需要變化 77 { 78 Distribute(L,i,f,e); 79 Collect(L,i,f,e); 80 } 81 } 82 83 int main() 84 { 85 int n; 86 scanf("%d",&n); 87 SLList L; 88 L.length=n; 89 L.r[0].next=1; 90 for(int i=1;i<=n;i++) 91 { 92 scanf("%d",&L.r[i].key); 93 L.r[i].next=i+1; 94 } 95 L.r[n].next=0; 96 RadixSort(L); 97 Print_L(L); 98 return 0; 99 }
鏈式時間復雜度:
順序實現:

1 //庫函數頭文件包含 2 #include<stdio.h> 3 #include<malloc.h> 4 #include<stdlib.h> 5 6 7 //函數狀態碼定義 8 #define TRUE 1 9 #define FALSE 0 10 #define OK 1 11 #define ERROR 0 12 #define INFEASIBLE -1 13 #define OVERFLOW -2 14 #define Radix 10 15 #define maxn 100010 16 typedef int Status; 17 typedef int QElemType; 18 19 typedef struct QNode 20 { 21 QElemType data; 22 struct QNode *next; 23 }QNode, *QueuePtr; 24 25 typedef struct 26 { 27 QueuePtr front; 28 QueuePtr rear; 29 }LinkQueue; 30 31 Status InitQueue(LinkQueue &Q) 32 { 33 Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode)); 34 if(!Q.front) 35 exit(OVERFLOW); 36 Q.front->next=NULL; 37 return OK; 38 } 39 Status DestroyQueue(LinkQueue &Q) 40 { 41 while(Q.front) 42 { 43 Q.rear=Q.front->next; 44 free(Q.front); 45 Q.front=Q.rear; 46 } 47 return OK; 48 } 49 Status EnQueue(LinkQueue &Q,QElemType e) 50 { 51 QueuePtr p=(QueuePtr)malloc(sizeof(QNode)); 52 if(!p) 53 exit(OVERFLOW); 54 p->data=e; 55 p->next=NULL; 56 Q.rear->next=p; 57 Q.rear=p; 58 return OK; 59 } 60 Status DeQueue(LinkQueue &Q,QElemType &e) 61 { 62 if(Q.front==Q.rear) 63 return ERROR; 64 QueuePtr p=Q.front->next; 65 e=p->data; 66 Q.front->next=p->next; 67 if(Q.rear==p) 68 Q.rear=Q.front; 69 free(p); 70 return OK; 71 } 72 Status QueueEmpty(LinkQueue Q) 73 { 74 if(Q.front==Q.rear) 75 return TRUE; 76 else 77 return FALSE; 78 } 79 typedef struct 80 { 81 int key; 82 }SLNode; 83 typedef struct 84 { 85 SLNode r[maxn]; 86 int length; 87 }SLList; 88 LinkQueue B[Radix]; 89 int Ord(int k,int j) 90 { 91 for(int i=1;i<j;i++) 92 k/=10; 93 k%=10; 94 return k; 95 } 96 void Print_L(SLList L) 97 { 98 int mrk=0; 99 for(int p=1;p<=L.length;p++) 100 { 101 if(mrk) 102 printf(" "); 103 printf("%d",L.r[p].key); 104 mrk=1; 105 } 106 printf("\n"); 107 } 108 void Distribute(SLList &L,int i) 109 { 110 for(int j=1;j<=L.length;j++) 111 { 112 int k=Ord(L.r[j].key,i); 113 EnQueue(B[k],L.r[j].key); 114 } 115 } 116 void Collect(SLList &L) 117 { 118 int i=1; 119 for(int j=1;j<Radix;j++) 120 { 121 while(!QueueEmpty(B[j])) 122 DeQueue(B[j],L.r[i++].key); 123 } 124 } 125 void RadixSort(SLList &L) 126 { 127 for(int i=0;i<Radix;i++) 128 { 129 InitQueue(B[i]); 130 } 131 for(int i=1;i<=6;i++) //最高位數為6,可根據實際變化 132 { 133 Distribute(L,i); 134 Collect(L); 135 } 136 } 137 int main() 138 { 139 int n; 140 scanf("%d",&n); 141 SLList L; 142 L.length=n; 143 for(int i=1;i<=n;i++) 144 { 145 scanf("%d",&L.r[i].key); 146 } 147 RadixSort(L); 148 Print_L(L); 149 return 0; 150 }
順序時間復雜度:
(由於我們所用教材為嚴蔚敏老師編寫的,所以代碼風格接近,也易於讀懂。
堅持不懈地努力才能成為大神!