Introduction to Algorithm(chapter 8)

基於比較的排序都有一個下界w(n*lgn),因爲基於比較的排序都可以通過建立一顆決策樹來表示,其中葉子節點代表最終的排序結果,這顆樹共有n!個葉子,那其中從根到葉子的最長路徑就代表了最壞情況下的比較次數,即樹的高度h。對於一顆h高的樹,葉子節點不多2^h,而這顆決策樹的葉子個數爲n!故,n!<=2^h..->  h>=lg(n!) = w(n*lgn),故基於比較的排序都有此下界。

而計數排序則不是基於比較的排序,它利用了元素的大小特點並採用一定的輔助空間來完成排序,假設一組數A[n](序號0...n-1),其中每一個元素大小在0...k之間,那麼就可以利用一個輔助數組C[k+1](序號0...k)來完成排序,先初始化C[i]=0,然後遍歷A[i],統計每個A[i]出現的次數即C[A[i]]++,這步操作後C[i]就代表i一共出現了多少次,然後遍歷C並

C[i] = C[i]+C[i-1],這步操作後C[i]就代表了小於等於i的元素共出現了多少次,例如假設A[i] = 5,C[A[i]]= 3,那麼就代表小於等於5的元素出現了三個,那麼我們就應該將5放在第三個位置上即B[C[A[i]]-1] = A[i](注意第三個位置對應於C語言中的B[2]故C[A[i]]-1對應於C語言中的下標),因爲可能存在不止一個5,所以放置過5後,我們要減少小於等於5出現的次數即C[A[i]]--,這樣如果還有5出現的話那麼它應該放置在第二個位置上。

算法:

// a array of n elements whose element is between 0---k
void countSort(int A[],int B[],int n,int k)
{
int* C = new int[k+1];//對應於0...k
for(int i=0;i<=k;i++)
C[i] =0;
for(int i=0;i<n;i++)
C[A[i]]++;//C[i]:i出現的次數
for(int i=1;i<=k;i++)
C[i] = C[i]+C[i-1];//C[i]:小於等於i的個數
print(C,k+1);

       //注意這裏採用的是從後往前遍歷,這樣就保證了算法的穩定性,假如初始A中有兩個相同的數...6....6,而且C[6] =  //10,那麼從後往前遍歷時遇到第一個6時將6放置在10位置處同時C[6]-- = 9,往前遍歷遇到第二個6時那麼這個6就放  //置在9位置處,這樣就保證了計數排序是穩定的。
for(int j =n-1;j>=0;j--) 
{
B[C[A[j]]-1] = A[j];//將每個A[j]放在和自己排名對應的地方
C[A[j]]--;//可能出現多個A[j],故減1以使下一次出現時將它放在前一個位置上而不重疊
}
delete []C;
}

計數排序思想有點類似於考試排名,給每個學生一個排名,那麼對結果排序時就應該將該學生信息放到和排名對應的欄目中,如果出現考試排名相同的情況那麼即將相同的放到前一個位置,不同點即是計數排序利用了元素本身大小的信息而考試排名沒用到,但將信息放到和排名對應的位置這點思想還是相似的。

 

習題8後面有個水壺配對的思考題,這個問題的答案很精彩,利用了快排的的思想,值得關注。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章