【演算法導論】9.中位數和順序統計量
在一個由n個元素組成的集合中,第i個順序統計量是該集合中第i小的元素。一箇中位數是它所屬集合的“中點元素”。中位數總是出現在上中位數處和下中位數處,本書中所用的“中位數”都是指下中位數。
本章討論的問題是,從一個由n個互異的元素構成的集合中選擇第i個順序統計量的問題,假設集合中的元素都是互異的。問題可被形式化定義為:
輸入:一個包含n個(互異的)數的集合A和一個整數i,1<=i<=n.
輸出:元素x屬於A,且A中恰好有i-1個其它元素小於它。(即在增序情況說下,x為第i 個元素)。
9.1最小值和最大值
對於確定單個最小值(最大值)的問題,能得到的下界就是n-1次比較,即需要遍歷整個陣列進行比較。
Minimum(A)
{
min=A[1];
for i=2 to A.length
if min>A[i]
min=A[i];
return min
}
同時找最小值和最大值,如果分別獨立地找出最小值和最大值,需要共2n-2次比較。
採用另一種方法:記錄已知的最小值和最大值(上面的做法是用每一個輸入元素與當前的最小值和最大值進行比較,這樣每個輸入值都需要比較兩次),對輸入元素進行成對處理。先將一對輸入元素相互進行比較,然後把較小的與當前最小值比較,把較大的與當前最大值進行比較,這樣每兩個元素需要3次比較。此時的比較次數為
設定已知的最小值和最大值的初始值依賴於n是奇數還是偶數。當n是奇數時,最大值和最小值的初始值都設為第一個元素的值,然後成對的處理剩下的元素。如果n是偶數,就對前兩個元素做一次比較,決定最大值和最小值的初值,然後成對的處理剩下的元素。
9.2期望為線性時間的選擇演算法
解決選擇問題的分治演算法,期望執行時間為(n)。
Randomized-Select(A, p, r, i)//返回陣列A[p..r]中第i小的元素 { if p==r//此時A中只包括一個元素,直接返回 return A[p]; q=Randomized-Partition(A, p, r); k=q-p+1; if i==k//檢查A[q]是否是第i小的元素 return A[q];//如果是的話,就返回A[q] else if i<k//否則就要確定第i小的元素落在哪個子陣列 return Randomized-Select(A, p, q-1, i); else return Randomized-Select(A, q+1, r, i); }
Randomized-Select的最壞情況執行時間為(n^2),因為在每次劃分時可能總是按餘下的元素中最大的來進行劃分,劃分操作需要(n)時間。同時,該演算法有線性期望執行時間,因為它是隨機化的,所以不存在一個特定會導致其最壞情況發生的輸入資料。
9.3最壞情況為線性時間的選擇演算法
一個最壞時間為O(n)的選擇演算法。像Randomized-Select一樣,Select演算法通過對輸入陣列的遞迴劃分來找出所需元素。但是在該演算法中能夠保證得到對陣列的一個好的劃分。通過執行下列步驟,演算法select可以確定一個有n>1個不同元素的輸入陣列中第i小的元素。(如果n=1,則select只返回它的唯一輸入數值作為第i小的元素)。
1. 將輸入陣列的n個元素劃分為(向下取整(n/5))組,每組5個元素,且至多隻有一組由剩下的nmod5個元素組成。
2.尋找這(向上取整(n/5))組中每一組的中位數:首先對每組元素進行插入排序,然後確定每組有序元素的中位數。
3.對第2步中找出的(向上取整(n/5))箇中位數,遞迴呼叫select以找出其中位數x(如果有偶數箇中位數,為了方便,約定x是較小的中位數)。
4.利用修改過的Partition版本,按中位數的中位數x對輸入陣列進行劃分。讓k比劃分的低區中的元素數目多1,因此x是第k小的元素,並且有n-k個元素在劃分的高區。
5.如果i=k,則返回x。如果i<k,則在低區遞迴呼叫select來找出第i小的元素。如果i>k,則在高區遞迴查詢第i-k小的元素。
(程式碼下次補)。
時間複雜度為O(n)。