數據結構基礎(15) --基數排序

  基數排序是一種藉助“多關鍵字排序”的思想來實現“單關鍵字排序”的內部排序算法。

實現多關鍵字排序通常有兩種作法:

   最低位優先法(LSD)

    先對K[0]{基數的最低位}進行排序,並按 K(0) 的不同值將記錄序列分成若干子序列之後,分別對 K[1] 進行排序,..., K[d-1]依次類推,直至最後對最次位關鍵字排序完成爲止。

  最高位優先法(MSD)

    先對 K[d-1]{基數的最高位}進行排序,然後對 K[d-2]進行排序,依次類推,直至對最主位關鍵字 K[0] 排序完成爲止。

 

百度百科對基數排序做了如下介紹:

    基數排序(radix sort)是屬於“分配式排序”(distribution sort),基數排序法又稱“桶子法”(bucket sort),顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,在某些時候,基數排序法的效率高於其它的穩定性排序法。

 

鏈式基數排序基本步驟如下

    1.將待排序記錄以數組存儲[或者以指針相鏈,構成一個鏈表]

    2.”分配”時,按當前”關鍵字位”所取值,將記錄分配到不同的”鏈表/鏈隊列”(即不同的桶或堆中)中,每條鏈表中記錄的”關鍵字位”相同;

    3.”收集”時,按當前關鍵字位取值從小到大(即將這n條鏈表(n的大小爲基數的大小)按照編號, 依次將其中所有的元素取出)將各鏈表中的元素取出放入到原先的數組或鏈表中;

    4.對每個關鍵字位均重複 2) 和 3) 兩步n次。

 

如採用LSD對{179, 208, 306, 93, 859, 984, 55, 9, 271, 33}(構成一個鏈表或者是數組)進行基數排序:

[第一步:按個位排]

 

[第二步:按十位排]


[第三步:按百位排]

 

代碼實現(LSD爲例):

  1. //尋找數組中最大數字的位數  
  2. template <typename Type>  
  3. unsigned int maxBits(Type *begin, Type *end)  
  4. {  
  5.     unsigned int bits = 1;  
  6.     //standard作爲基準, 如果array中的元素  
  7.     //大於standard, 則bits+1  
  8.     int standard = 10;  
  9.   
  10.     for (Type *current = begin; current != end; ++current)  
  11.     {  
  12.         while (*current >= standard)  
  13.         {  
  14.             standard *= 10;  
  15.             ++ bits;  
  16.         }  
  17.     }  
  18.   
  19.     return bits;  
  20. }  
  1. /**說明: 
  2.   begin:數組起始 
  3.   end:數組結尾 
  4.   radix:基數 
  5.  
  6. */  
  7. #define DEBUG  
  8. template <typename Type>  
  9. void radixSort(Type *begin, Type *end, int radix)  
  10. {  
  11.     //找到數組中最大數字的位數  
  12.     int bits = maxBits(begin, end);  
  13.   
  14.     //基數爲radix, 則需要radix個鏈表  
  15.     std::list<Type> lists[radix];  
  16.   
  17.     // 需要循環bits次  
  18.     for (int d = 0, factor = 1; d < bits; ++d, factor*=10)  
  19.     {  
  20.         //分配...  
  21.         for (Type *current = begin; current != end; ++current)  
  22.         {  
  23.             //取出相應位置上的數 (比如個位是1)  
  24.             int number = ((*current)/factor)%10;  
  25.             //則需要將之放到(分配到)標號爲1的鏈表中  
  26.             lists[number].push_back(*current);  
  27.         }  
  28.   
  29.         //收集...  
  30.         Type *current = begin;  
  31.         //對radix個鏈表中的元素進行收集  
  32.         for (int i = 0; i < radix; ++i)  
  33.         {  
  34.             while (!lists[i].empty())  
  35.             {  
  36.                 *current = lists[i].front();  
  37.   
  38.                 ++ current;  
  39.                 lists[i].pop_front();  
  40.             }  
  41.         }  
  42. #ifdef DEBUG  
  43.         //打印排序的中間結果  
  44.         for (current = begin; current != end; ++ current)  
  45.         {  
  46.             cout << *current << ' ';  
  47.         }  
  48.         cout << endl;  
  49. #endif // DEBUG  
  50.     }  
  51. }  
  52.   
  53. template <typename Type>  
  54. void radixSort(Type *array, int arraySize, int radix)  
  55. {  
  56.     return radixSort(array, array+arraySize, radix);  
  57. }  

時間複雜度分析:

    設待排序列爲n個記錄,d個關鍵碼,關鍵碼的取值範圍爲radix,則進行鏈式基數排序的時間複雜度爲O(d(n+radix)),其中,一趟分配時間複雜度爲O(n),一趟收集時間複雜度爲O(radix),共進行d趟分配和收集.


-測試代碼:

  1. int main()  
  2. {  
  3.     int array[10];  
  4.     for (int i = 0; i < 10; ++i)  
  5.     {  
  6.         array[i] = rand()%1000;  
  7.     }  
  8.     for (int i = 0; i < 10; ++i)  
  9.     {  
  10.         cout << array[i] << ' ';  
  11.     }  
  12.     cout << endl;  
  13.   
  14.     radixSort(array, 10, 10);  
  15.   
  16.     for (int i = 0; i < 10; ++i)  
  17.     {  
  18.         cout << array[i] << ' ';  
  19.     }  
  20.     cout << endl;  
  21.   
  22.     return 0;  


原文地址:http://blog.csdn.net/zjf280441589/article/details/42609453

發佈了62 篇原創文章 · 獲贊 16 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章