1. 程式人生 > >桶排序和計數排序

桶排序和計數排序

node [] 無法 () cnblogs 遍歷 nts 定義 操作

突然想自己寫個桶排序,然後做課後題又發現了計數排序,覺得挺有趣的。不過書上都沒有給代碼,所以就自己寫了一下代碼,超級爛0 0下面先簡單介紹下這兩種排序

桶排序

桶排序,就是根據散列的思想進行數據的排序。假設有M個桶,采用最簡單的hash(key)=key,這樣無需比較,就可以把數存入相應的桶中。針對沖突排解問題,此時查找鏈的方式顯然不再適用,采用獨立鏈法,把每個桶以鏈表的形式存儲雷同元素,定義相同元素的偏序,這樣能實現排序的穩定性。桶排序完全采用了簡單的哈希策略,是比較容易理解的。同時,完全摒棄了CBA式的方式,從而可以突破復雜度O(nlogn)的界限。通過空間換時間的策略,可以達到O(n)的時間復雜度,代價是O(M+N)的額外空間。下面是對於整型數組的桶排序,代碼很爛我也沒有改,已經測試過:

 1 struct node 
 2 {
 3     node(int v = 0, node* s = NULL) :value(v), succ(s) {}
 4     int value;
 5     node* succ;
 6 };
 7 void insert(node &a, int b)//b插入到a後面
 8 {
 9     node* t = new node(b);
10     if (a.succ) t->succ = a.succ;
11     a.succ = t;
12 }
13 node* bucketSort(int* A, int n, int
k)//數的範圍為[0,k) 14 { 15 node* bucket = new node[k](); 16 for (int i = 0; i < n; i++) 17 insert(bucket[A[i]],A[i]); 18 return bucket; 19 } 20 void show(node a) 21 { 22 while (a.succ) 23 { 24 a = *(a.succ);//第一個節點作為哨兵不輸出 25 cout << a.value << " "; 26
} 27 } 28 int main() 29 { 30 int A[15] = { 2,0,1,3,3,0,1,9,7,7,15,11,13,12,10}; 31 node* p = bucketSort(A, 15, 16); 32 for (int i = 0; i < 16; i++) 33 show(p[i]); 34 system("pause"); 35 return 0; 36 }

下面有測試例子,已經經過了測試,不過這裏僅把排序的結果存入了一個申請空間的列表然後輸出,沒有進行釋放的操作,也沒有存入原數組或者另外一個數組0 0看具體的要求可以改動

計數排序

計數排序的基本策略,基於這樣的事實:一個有序序列,元素m的秩,應當等於序列中全部元素中,小於等於m的元素數量。所以計數排序算法可以歸納如下:遍歷序列,對於每個元素,再遍歷整個序列,用一個額外的數組進行計數。不難看出,時間復雜度為O(n^2)。顯然,無法接受這樣的復雜度。

可以考慮用散列的方法來降低復雜度。同樣,對於[0,k)的元素,選取M個桶,假設元素數量為n,先遍歷序列,用桶數組進行計數。隨後,每一個後面的桶的計數=前面桶的數量+它自身的計數。這樣,每個桶的數字-1就等於桶對應元素的秩。同時,也可以處理相同元素的問題,因為當元素存在其他因素的偏序時,數字也加在了桶數組的計數中,桶數組只需要從後向前輸出,就可以維持這種偏序。實現代碼如下:

 1 /*計數排序*/
 2 int* countSort(int* A,int k,int n)//[0,k)範圍內n個數
 3 {
 4     int* tmp = new int[k];
 5     int* s = new int[n];
 6     memset(tmp, 0, sizeof(int) * k);
 7     for (int i = 0; i < n; i++)//原始數組中的計數
 8         tmp[A[i]]++;
 9     for (int i = 0; i < k - 1; i++)//記錄不大於該數的數字個數
10         tmp[i + 1] += tmp[i];
11     for (int i = n - 1; i >= 0; i--)//逆序輸出
12         s[--tmp[A[i]]] = A[i];//計數哈希數組-1即為應當對應的秩,用原數組的數賦值
13     delete[] tmp;
14     return s;
15 }

代碼已經經過了測試。可以看到,只需要兩趟原數組遍歷,一趟桶數組遍歷即可完成,時間復雜度為O(M+n)。同樣,輔助空間為桶數組,空間復雜度為O(M)。不難看出,計數排序適用的最合適情況,是M遠小於n的時候,即數據較多而範圍確不大。此時,時間復雜度僅為O(n)。

桶排序和計數排序