基數排序(Radix sort)是一種非比較型整數排序演算法,其原理是將整數按位元切割成不同的數字,然後按每個位元分別比較。由於整數也可以表達字串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是只能使用於整數。基數排序的發明可以追溯到1887年赫爾曼·何樂禮在打孔卡片製表機(Tabulation Machine)上的貢獻。時間複雜度是 O(k·n),其中n是排序元素個數,k是數字位元。——來自維基百科
空間複雜度為O(B),其中B為基數Base,如10或16等,不是一個穩定排序。
維基百科上有C++實現的代碼,夠簡練,看了一段時間才看明白,在每次基於各個數位上的數字散列和合并的時候,用的方式夠巧妙,是我沒想出來的!特在此處貼出來,然後解釋之~
我仿著維基百科給的C++代碼,實現如下:
#include <iostream>#include <cstring>#include <ctime>using namespace std;struct Num{int v;Num *next;Num(){next=0;}};void sort(int *arr,int len){const int RADIX=10;//以10為基進行排序int tmp;Num *topBox[RADIX];//桶中最新添加進去的元素Num *bottomBox[RADIX];//桶底元素for(int i=0;i<RADIX;++i){topBox[i]=bottomBox[i]=new Num;}//找最大值tmp=arr[0];for(int i=0;i<len;++i){if(tmp<arr[i])tmp=arr[i];}//計算最大值有多少個數位int digCnt=1;tmp/=RADIX;while(tmp){++digCnt;tmp/=RADIX;}//將數群組轉換成鏈表Num *head=new Num;Num *cur;cur=head;for(int i=0;i<len;++i){cur->next=new Num;cur->next->v=arr[i];cur=cur->next;}//開始基數排序int factor=1;for(int i=0;i<digCnt;++i){//散列for(cur=head->next;cur;cur=cur->next){tmp=(cur->v/factor)%RADIX;topBox[tmp]->next=cur;topBox[tmp]=topBox[tmp]->next;}//合并cur=head;for(int j=0;j<RADIX;++j){if(topBox[j]!=bottomBox[j]){cur->next=bottomBox[j]->next;cur=topBox[j];topBox[j]=bottomBox[j];}}//必須將最後一個數位next賦值為NULL,否則導致鏈表形成環,導致再次"散列"時會死迴圈cur->next=0;//擴大因子,用於取下一個數字factor*=RADIX;}//使用鏈表給數組賦值cur=head->next;for(int i=0;i<len;++i,cur=cur->next){arr[i]=cur->v;}}void test(){int len=20;int *heap=new int[len];srand(time(0));for(int i=0;i<len;++i){heap[i]=rand()%10000;}cout<<"初始數組:"<<endl;printArray(heap,len);//mySort(heap,0,len-1);sort(heap,len);printArray(heap,len);delete heap;}
bottomBox數組不會變化,因為它儲存的是每個“桶”的初始元素,而topBox數組一直在變化,因為它始終指向“桶”中最近被添加的數字,這是由"基數排序中的每個"桶"必須在鏈表尾部添加新的數字"決定的,鏈表的尾部,就是topBox(可以把這個"桶"想象成一個開口向下的倒著的桶~)。起始狀態,bottomBox與topBox裡的每個元素都是一樣的,因為每個"桶"裡都沒有數字,隨著散列的進行,有些"桶"裡就被先後放入多個數字,此時topBox隨之變化,使自己總是指向"桶"最頂部的數字,也就是最新被添加的那個數字。
散列完成之後,需要將本次的散列結果按“在數組中散列到的桶號”串聯起來,用於下次散列,串聯的時候,每個“桶”中,開始的元素由bottomBox儲存,終止元素由topBox儲存,而且,如果該“桶”是空的,那麼bottomBox對應的值與topBox對應的值相等,反過來說:凡是bottomBox中與topBox對應值不相等的那個“桶”裡肯定有數字串,這個串的起始數字由bottomBox儲存,終止數字由topBox儲存。很巧妙吧!