1. 程式人生 > >分治演算法解決一個最壞O(N)時間的選擇問題

分治演算法解決一個最壞O(N)時間的選擇問題

分治演算法的一個基礎定理如下

定理1:若\sum_{i=1}^{k}a_{i}<1,則方程T(N)=\sum_{i=1}^{k}T(a_{i}N)+O(N)的解是T(N)=O(N)

意思是,把原問題分解成若干子問題,若這些子問題的規模之和沒有原問題大,那麼再加上處理這些子問題的O(N)時間,演算法的時間界是O(N)

選擇問題:在N個數中抽取第k小的,有幾種解法:

1.可以用優先佇列得到一個O(klogN)或者O(Nlogk)的時間,若k是中位數那麼時間就是O(NlogN)

2.可以使用快速選擇演算法,每次處理一個不到原問題的子問題和線性附加時間,平均時間O(N),但是無法保證樞紐元的壞選擇,因此最壞時間是O(N^2)

3.先將元素排序,自然可以得到第k小的數字,時間是O(NlogN)

以上幾種解法中,快速選擇演算法在實踐中應用最好,但是仍然無法達到O(N)最壞時間,根本原因是樞紐元的選擇無法保證定理1成立。一般樞紐元的選擇是三數中值法,但是若3個數都是最大元,那麼是壞選擇;可以增加使用的數字數量,用常數時間排序,得到中位數,由於按照定理1只能有常數附加時間,因此使用的數字個數最多可以達到O(\frac{N}{logN})

,對其進行排序,花費時間O(N),顯然不能超過這個數字,否則附加時間會超過O(N)。然而,在最壞情況下,還是不行,因為可能選擇到O(\frac{N}{logN})個最大的元素,那麼樞紐元是第O(N-\frac{N}{logN})個元素,每次處理的子問題是O(N-\frac{N}{logN}),這不是N的常數部分,無法應用定理1

五分化中項的中項:改進樞紐元選擇如下:

1.把N個元素分成\left \lfloor N/5 \right \rfloor組,5個元素一組,剩餘不到5個的一組可以忽略

2.找出每組的中項,得到\left \lfloor N/5 \right \rfloor箇中項的表M

3.求出M的中項,將其作為樞紐元返回

定理2:使用五分化中項的中項進行樞紐元選擇,快速選擇演算法最壞時間O(N)

證明:

N=10k+5,可以這樣假設不影響時間界的計算,如下圖:

其中,每一列是5個元素的一組,中間的格子是5個元素的中項,第三行就是所有中項,所有中項的中項用Mid表示,一共2k+1組,顯然有k組中,每組有3個元素比Mid大,一共3k個元素,Mid自己所在的組有2個比Mid大,一共3k+2個一定比Mid大的,比Mid小的數字數量同理,這樣每次處理的子問題大小最大可以達到0.7N,就是原問題的0.7倍。

到這裡得到了子問題最壞的大小,還有兩項附加工作要做:

1.在每個組中,在5個元素中選擇中項花費時間是常數,所有組就是O(N)時間

2.在0.2N箇中項中選擇中項,若用排序,那麼需要O(NlogN)時間,顯然不行,因此需要對這些數字遞迴呼叫選擇演算法

綜上,一次遞迴呼叫,解決0.7N大小和0.2N大小的兩個子問題,加上O(N)線性時間,滿足定理1要求,得到一個O(N)的最壞時間