分治法 線性時間選擇

2021-10-25 02:03:55 字數 1792 閱讀 3119

問題:給定線性序集中n個元素和乙個整數k,1≤k≤n,要求找出這n個元素中第k小的元素,演算法的複雜度為o(n)。

思路分析:

首先,假如我們要找最大或者最小的元素,那麼只需遍歷一遍序列即可,複雜度為o(n)。假如要找第k大的元素,k<=n/logn或者k>=n-nlogn時,利用堆排序,時間複雜度仍然可以達到o(n),具體為什麼還沒搞懂。無論如何,如果對於任意的k,(最壞)時間複雜度要想達到o(n),對整個序列進行排序都是不可行的(複雜度至少為nlogn)。

那麼如何將複雜度降低到o(n)呢?由於我們求的僅僅是第k大的數字,那麼可以不用整個對整個序列進行排序,而僅僅保證在第k大的數字前面的數字都小於這個第k大數即可。借助快排的思想,每次找乙個哨兵將序列分為大於哨兵和小於哨兵的兩部分,根據需要求的數是第k**擇乙個子串行遞迴進行排序即可,而非對所有的序列都要排序。

假如能夠做到在任意情況下,所選的哨兵將序列等比地分為兩部分,就可以做到線性地得到結果:設子串行的長度分別為ne和n(1-e),複雜度遞推公式為t(n) = t(ne)+o(n),時間複雜度為o(n)。

如何保證在任意情況下哨兵都會做到等比分割序列呢?傳統的快速排序演算法在選取哨兵時採用序列的第乙個元素,這樣在極端情況下會退化為等差遞減的遞迴,也就是冒泡;隨機快速排序演算法對此進行了一些優化,每次隨機選取哨兵,但是本質上也是一樣。將序列預劃分可以有效地解決這一問題:

1.將序列劃分成n/5個子序列,每個子串行有5個元素,最後乙個不足5個元素的子串行扔掉不要(因為目的只是為了找乙個差不多的基準哨兵),任選一種排序方法對每個子串行進行排序,對每個子串行取中位數

2.取出中位數後,對n/5個中位數再取中位數,這裡其實轉化為中位數中求解第k大的數的子問題

3.以確定的中位數作為哨兵,進行劃分序列,可以證明,當n>=75時,此時子串行近似劃分為n/4和3n/4兩個部分

複雜度遞推公式為t(n)=t(n/5)+t(3n/4)+o(n),n>=75;t(n)=o(1),n<75

**:

// 將序列a重排為mid左邊的元素全部小於mid,mid右邊的元素全部大於mid

// 輸入:序列a,序列起始下標l,終止下標r,哨兵大小mid

// 輸出:mid在序列a中的位置j,據此可確定劃分完成的兩個子串行

int part(int a,int l,int r,int mid)

while(a[j]>=mid)

if(i>=j)else

}return j;

}// 選取序列a中序號從l到r中第k小的元素

// 輸入:序列a,序列起始下標l,序列終止下標r,所求的元素是第k小

// 輸出:第k小的元素大小

int select(int a,int l,int r,int k)else

// 獲取中位數的中位數

int mid = select(a, l, l+(r-l-4)/5, ((r-l-4)/5+1)/2);

// 以mid為基準進行子串行的劃分

int mid_id = part(a, l, r, mid);

int mid_rank = mid_id - l + 1;

// 判斷應該取哪個子串行進行遞迴

if(k == mid_rank)

return a[mid_id];

else if(k > mid_rank)

return select(a, mid_id+1, r, k-mid_rank);

else

return select(a, l, mid_id-1, k);

}}

分治法 線性時間選擇

演算法思想 利用快速排序的方法將a p r 被劃分成兩個子陣列a p i 和a i 1 r 使a p i 中的每個元素都不大於a i 1 r 中每個元素。接著演算法計算子陣列a p i 中元素個數j。如果k j,則第k小的數落在左區間,否則落在右區間,直到k j時,找到第k小的數。對於有重複數字的無...

分治法 線性時間選擇(求第k小數)

給定線性序集中n個元素和乙個整數k,1 k n,要求找出這n個元素中第k小的元素,這裡給定的線性集是無序的 線性時間選擇隨機劃分法可以模仿隨機化快速排序演算法設計。基本思想是對輸入陣列進行遞迴劃分,與快速排序不同的是,它只對劃分出的子陣列之一進行遞迴處理。利用隨機函式產生劃分基準,將陣列a p r ...

演算法 線性時間選擇 C C

給定線性序集中n個元素和乙個整數k,n 2000000,1 k n,要求找出這n個元素中第k小的數。第一行有兩個正整數n,k.接下來是n個整數 0 ai 1e9 輸出第k小的數 6 3 1 3 5 2 4 6 3利用快速排序可以找出第k小的,加上隨機函式改進一下 ac include include...