線性時間選擇(C ) 求第k小的數

2021-09-26 20:33:27 字數 2440 閱讀 2177

思想:首先對整個陣列進行劃分,利用partition函式,以陣列中某個數為基準(這裡以首項為標準)將陣列劃分為兩部分——左邊部分的所有數都小於基準,右邊部分都大於基準,並返回基準數的下標值。

然後,如果要找到第k小個數,就將k的大小與陣列左半邊元素的個數(若為 j,包括基準)進行比較,如果k小於j,則對左邊部分進行遞迴,找第k小個數;若k大於j,則對右邊部分進行遞迴,找第k減去j個小數。

#includeusing namespace std;

templateint partition(t a, int l, int r)

a[l] = a[j];

a[j] = x;

return j;

}templatet select(t a, int left, int right, int k)

int main()

分析一下partition函式:

以陣列 a = 為例,首先以3為基準,令x=a[0](一般寫為x=a[left], left為陣列左邊的最小下標值),i= 0,

j=6+1(最大下標值加一),接著進迴圈。i自增1,判斷a[i]是否小於x,若小於則繼續往下判斷,否則退出迴圈。然後,j自減1,判斷a[j]是否大於x,若大於繼續迴圈,否則退出迴圈。可知第一次退出時,i=2,j=3。然後交換a[i]與a[j]的值,陣列變為,繼續迴圈,直到i>=j時退出迴圈,可知退出迴圈時i=3,j=2。將a[0]與a[j]的值交換,返回下標j旳值。陣列變為

左半部分(下標值小於2的部分)都小於基準x,即3,右邊都大於3。

例如,若ε=9/10,演算法遞迴呼叫所產生的子陣列的長度至少縮短1/10。所以,在最壞情況下,演算法所需的計算時間t(n)滿足遞迴式t(n)≤t(9n/10)+o(n) 。由此可得t(n)=o(n)。

步驟:(1)將n個輸入元素劃分成n/5(向上取整)個組,每組5個元素,最多隻可能有乙個組不是5個元素。用任意一種排序演算法,將每組中的元素排好序,並取出每組的中位數,共n/5(向上取整)個。

(2)遞迴呼叫select來找出這n/5(向上取整)個元素的中位數。如果n/5(向上取整)是偶數,就找它的2個中位數中較大的乙個。以這個元素作為劃分基準。

例子:按遞增順序,找出下面29個元素的第18個元素:8,31,60,33,17,4,51,57,49,35,11,43,37,3,13,52,6,19,25,32,

54,16,5,41,7,23,22,46,29.

(1) 把前面25個元素分為5(=floor(29/5))組:  (8,31,60,33,17),(4,51,57,49,35),(11,43,37,3,13),(52,6,19,25,32),(54,16,5,41,7);

(2) 提取每一組的中值元素,構成集合;

(3) 遞迴地使用演算法求取該集合的中值,得到m=25;

(4) 根據m=25, 把29個元素劃分為3個子陣列(按原有順序)

p=q=

r=(5) 由於|p|=13,|q|=1,k=18,所以放棄p,q,使k=18-13-1=4,對r遞迴地執行本演算法;

(6) 將r劃分成3(floor(15/5))組:,,

(7) 求取這3組元素的中值元素分別為:,這個集合的中值元素是43;

(8) 根據43將r劃分成3組: ,,

(9)將左半邊元素的個數與18作比較,若小於18,則對右邊進行遞迴,否則對左邊進行遞迴。

參考文章:

#includeusing namespace std;

templatevoid sort(t a, int m, int n) }}

templateint partition(t a, int l, int r,t midnum)

t df = a[l];

a[l] = a[point];

a[point] = df;

int i = l, j = r + 1;

t x = a[l];

while (true)

a[l] = a[j];

a[j] = x;

return j;

}templatet select(t a, int left, int right, int k)

for (int i = 0; i <= (right - left - 4) / 5; i++)

t x = select(a, left, left + (right - left - 4) / 5, (right - left - 4) / 10);

int local = partition(a, left, right, x), j = local - left + 1;

if (k <= j)

return select(a, left, local, k);

else

return select(a, local + 1, right, k - j); }

int main()

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

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

線性時間選擇 第k個數

採用的演算法思想和快速排序十分相似,選取基準進行一次快排,得到乙個基準和左側小於基準右側大於基準的陣列。然後判斷基準的位置,如果第k個數在左邊便接著向左遞迴,如果在右側便接著向右側遞迴。include include include include include include includeus...

線性時間選擇問題(找第k大的數)

給定線性序集中n個元素和乙個整數k,n 2000000,1 k n,要求找出這n個元素中第k小的數。第一行有兩個正整數n,k.接下來是n個整數 0 ai 1e9 輸出第k小的數 6 31 3 5 2 4 6 定義陣列a存放資料,由於資料較多,用scanf進行輸入。陣列從0開始存入資料,所以第k大的數...