插入,快速,合併,堆排序等基於比較的排序演算法的最壞情況下界為ω(nlogn),最壞情況下都要進行ω(nlogn)次比較。假設有一n個元素組成的陣列(假設每個元素都不相等),那麼一共有n!排列組合,而且這n!排列組合結果都應該在決策樹的葉子節點上(如圖1),在圖1中n = 3,所以有3! = 6種組合全都在決策樹的葉子節點,對於高度為h的二叉樹,葉子節點的個數最多為2h(當為滿二叉樹時為2h,這裡根節點為第0層)。所以n! <= 2h,從而h >= log(n!) = ω(nlogn)。證明如下:(如果不太了解o,θ等漸進符號的,可以參考博文:計算機演算法分析之漸進記號。)
假設:有n個數的集合,而且n個數的範圍都在0~k(k = o(n))之間。
待排序陣列a如圖2.1所示,需要輔助陣列b(儲存最後排序結果),陣列c(儲存元素的個數)。基於上述的假設,陣列c的大小為k,c[i]表示陣列a中元素i(0 <= i < k)的個數(如圖2.2所示),為了保證計數排序的穩定性,陣列c變化為圖2.3,c[i]表示小於或者等於i的個數。**如下:
/*
輸入:待排序陣列a,儲存排序後的陣列b,陣列a的大小,陣列c的大小
功能:計數排序
*/void countingsort(int a, int b, int len, int k)
for (i = 0; i < len; i++)
for (i = 1; i < k; i++)
// 從右至左保證演算法的穩定性
for (i = len-1; i >=0; i--)
}
9-12行和19-22行的執行時間θ(k),14-17行和25-29行的執行時間為θ(n),所以總的執行時間為θ(2(n+k)) = θ(n+k)。
基數排序:將所有待比較數值(正整數)統一為同樣的數字長度,數字較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後, 數列就變成乙個有序序列。
基數排序分為兩種lsd和msd。
lsd(least significant digital):最低有效位優先,即從右向左開始排序。
msd(most significant digital):最高有效位優先,即從左往右開始排序。
以下是lsd方式的基數排序的偽**
radixsort(a,d)
for i
用穩定的排序演算法排列陣列a中元素的第i位
如圖3:先牌個位,然後十位,最後百位。為陣列的某一位排序的時候一定需要穩定的演算法。
執行時間為θ(d(n+k))。在基數排序中排列陣列各位的演算法是計數排序所以執行時間為θ(n+k),又d是陣列中數的最大位數。
桶排序:將陣列分到有限個桶子內,然後再對桶子裡面的序列進行排序,執行時間θ(n)。桶排序基於乙個假設:輸入的資料由隨機過程構成,否則在最壞情況下都分配到乙個桶子裡面,如果又不滿足計數排序的假設要求,那麼只能使用基於比較的排序演算法進行排序,執行時間就退化到ω(nlogn)。
排序演算法穩定性:假設待排序序列中有兩個元素相等,而且在排序前和排序後兩個相等的元素的相對位置不變,即有 a = b,排序前a在b前面,那麼排序後,a還是要在b前面。排序演算法的穩定性是要看具體的演算法實現,比如一般情況下,直接選擇排序,快速排序,希爾排序,堆排序都不是穩定排序演算法,基數排序,計數排序,歸併排序,插入排序,氣泡排序都是穩定排序演算法。
快速排序:a = ,排序後a = 。
希爾排序:a = ,排序後(k = 2);a = 。
堆排序:a = ,排序後a = 。
直接選擇排序: a = ,排序後 a = 。
以上舉例都不滿足穩定性。
o n 線性排序演算法
前面有總結過各類常用的排序演算法,但是那些排序演算法平均的時間複雜度是o nlogn 所以我要介紹三種時間複雜度為o n 的線性時間複雜度的排序演算法。計數排序利用了雜湊的性質,將乙個中間陣列來記錄數值對應的下標,最後查詢對應的下標進行放置 步驟如下 找出待排序的陣列中最小和最大值,計算最大和最小值...
線性時間排序演算法
基於比較的演算法的時間下限為nlogn,而計數排序 桶排序和基數排序這幾種非比較演算法卻可以突破這個下限,僅管它們對輸入都有一定限制條件,即輸入資料必須在某個範圍內。但是,這些演算法還是非常實用的。閒著沒事,寫了一下 詳細見 演算法導論 define no cmp sort ifdef no cmp...
線性時間排序演算法
基於比較的演算法的時間下限為nlogn,而計數排序 桶排序和基數排序這幾種非比較演算法卻可以突破這個下限,僅管它們對輸入都有一定限制條件,即輸入資料必須在某個範圍內。但是,這些演算法還是非常實用的。閒著沒事,寫了一下 詳細見 演算法導論 define no cmp sort ifdef no cmp...