排序演算法 4 線性時間排序

2021-06-23 07:45:49 字數 2213 閱讀 6221

在前面三節排序演算法中,我們分別分析了不同策略,思想用於排序,而這些演算法都是基於資料間的比較來確定順序的。假設我不用比較,換一種思路,那麼就可以達到時間複雜度為o(n)的排序演算法,當然是以付出額外的空間為代價的。

線性時間排序的演算法思想:

(1):在計數排序中,利用比x小或等的元素個數和的來確定x位置。比如2 5 4 9 1 6.9比其餘5個數都大,那就說明9 在排序後的第6個位置,這樣我們只要得到比某個數大的元素個數就能得到元素在排序後陣列中的位置了。

(2):在桶排序中,是通過對映的方式,將大範圍內的數對映到[0,1]之間的10個桶在中,這樣再對每個桶中元素進行排序,將最後結果組合就行。本質也是分治的思想,不過這個分治有一定的規律,且分的子問題規模在一般情況下都很小,除了把元素都對映到少數幾個桶的情況。

計數排序的思想在前面已經闡述過了,前面舉的例子也比較簡單,我們沒有考慮出現多個元素是相同的情況,如果出現多個元素是相同的情況,那應該怎麼處理呢?多個元素不可能在同乙個位置,必然有先後順序,怎麼處理先後順序能決定計數排序的穩定性。下面結合圖和程式來說明

輸入的是陣列a,計數的陣列為c,利用c的陣列標號來計數,這裡標號有可能超過10,標號0存的a中0的個數,1存的是1的個數。存好後,計算大於等於a中元素的個數,如右圖,小於等於0的元素有1。

首先初始化計數陣列,大小要等於元素a中的最大元素,可以利用乙個迴圈求的,在下面程式未考慮,僅設定為a長度的兩倍。然後計算每個元素的個數並存在c對應標號的位置。計算大於等於a中元素的個數,從右向左掃瞄陣列a(為什麼不左向右)取元素成為c的標號,得出這一元素在輸出陣列中的位置,把元素存於在一位置。因為可能有多個元素都存在這一位置,所以需要把c的數值減一。

假設我後面掃瞄到相同大小的元素,我還是來取c的這個位置來確定排序後的元素所在位置,因為已經-1了,所以自然就排到前面的位置去了。這裡就保持了排序的穩定,也回答為什麼要從尾開始掃瞄。多個相同元素的前後位置保持一致。

基數排序是以計數排序為基礎的,實現在關鍵在於分離各個位數,以及在之前排序在基礎在進行排序。這裡的問題主要就是為什麼不同高位牌開始呢?假設從高位排開始,那麼對於每個位數就必須先儲存其他的,等最小的那個排好後,然後排大二小的。基數排序當然也可以用於位數不相等的資料,第一步就是求最大的位數,然後從低位開始應用計數排序,直到最高位。 

#include using

namespace

std;

const

int radix=10

;void radixsort(int a,int

n)

if (bi>mbi)

bi=0

; }

//從低位開始對陣列進行計數排序

for (int i=0;i)

for (int j=1;j)

count[j]+=count[j-1

];

for (int k=n-1;k>=0;k--)

for (int k=0;k)

rad=rad*radix;

}}int

main()

for(int i=0;i<10;i++)

cout

int data[10]=;

radixsort(data,k);

for(int i=0;i<10;i++)

cout

cout

<

return0;

}

參考

線性時間排序演算法

基於比較的演算法的時間下限為nlogn,而計數排序 桶排序和基數排序這幾種非比較演算法卻可以突破這個下限,僅管它們對輸入都有一定限制條件,即輸入資料必須在某個範圍內。但是,這些演算法還是非常實用的。閒著沒事,寫了一下 詳細見 演算法導論 define no cmp sort ifdef no cmp...

線性時間排序演算法

基於比較的演算法的時間下限為nlogn,而計數排序 桶排序和基數排序這幾種非比較演算法卻可以突破這個下限,僅管它們對輸入都有一定限制條件,即輸入資料必須在某個範圍內。但是,這些演算法還是非常實用的。閒著沒事,寫了一下 詳細見 演算法導論 define no cmp sort ifdef no cmp...

線性時間排序演算法

繼續上一次的排序演算法的總結,今天帶來的是線性時間排序演算法 可以看到,我們之前的交換演算法時間複雜度最少也只是o nlogn 那麼有沒有o n 的時間複雜度的演算法呢,也是有的,就是線性時間排序演算法。常見的線性時間演算法有 計數排序,基數排序和桶排序,而基數排序和桶排序十分類似,這裡只介紹更為普...