Top k問題(線性時間選擇演算法)

2022-09-08 17:51:13 字數 2097 閱讀 1670

問題描述:給定n個整數,求其中第k小的數。

分析:顯然,對所有的資料進行排序,即很容易找到第k小的數。但是排序的時間複雜度較高,很難達到線性時間,雜湊排序可以實現,但是需要另外的輔助空間。

演算法:linearselect(s,k)

輸入:陣列s[1:n]和正整數k,其中1<=k<=n;

輸出:s中第k小的元素

1. if  n<20  then  將s中的元素排序後輸出第k個元素,演算法結束;

2.將s劃分為無公共元素的 floor(n/5) 個分組,每組5個元素,第 i 個組記為si;

3.用插入排序演算法將每個組si 排序,求得中位數 mi ,其中 i=1,2,3,...,floor(n/5);

4.遞迴呼叫本演算法求得{mi | 1<=i floor(n/5)}的中位數(即第floor(n/10)小的元素)m;

5.劃分s為a={x|x屬於s 並且 xm};

6. if |a|>k  then  輸出 linearselect(a,k);

7. elseif  |a|+|b|8. else   輸出m,演算法結束;  

當然了,本題是求第k小,如果求第k大,可以轉換成對應的第n-k小,同樣可以求。這個演算法以後會經常用到,一定要掌握,但是如果資料量不超過20個的話,也可以直接排序求。

完整的j**a**如下,**寫法都比較通用,讀者可以很容易轉換為其他語言實現:

1

import

j**a.lang.math;

2import

j**a.util.arrays;

3import

j**a.util.scanner;

4public

class

topk

14 topk= s[k-1];15}

16else 25

26int sss=new

int[n/5];

27for(int i=0;i//

對應演算法的第三步

2833

arrays.sort(sss);

34int m=sss[n/5/2]; //

對應演算法的第四步

3536

int a=new

int[n]; //

對應演算法的第五步

37int b=new

int[n];

38int c=new

int[n];

39int a=0,b=0,c=0; //

作為三個結合的指標

40for(int i=0;i//

放入對應的集合中

4146

47if(a>k-1)topk=linearselect(a,a,k); //

對應演算法第六步,我定義的陣列是從下標0開始的忙,所以這裡是k-1

48else

if(a+b//

對應演算法第七步

49else topk=m; //

對應演算法第八步

5051}52

return topk; //

返回最終的top k53}

54public

static

void

main(string args) ;

57int n=6;

58int k=2;

59 system.out.print("陣列為:");

60for(int i=0;i)

6164

system.out.println();

65 system.out.println("第"+k+"小的數為:"+linearselect(s,n,k));

6667}68

69 }

view code

輸出結果為:

陣列為:16,9,92,40,25,27,

第2小的數為:16

TopK問題 線性時間選擇

相信計算機專業的同學應該都對快速排序有或多或少的了解。設定此模組是因為,線性時間選擇topk與快速排序的思想有相通之處,可以輔助我們理解。快速排序的思路 設定乙個瞭望元素 劃分元素 以此元素為基礎,將工作區間 l,r 內的所有元素分割成兩部分。劃分元素以左均比其小,劃分元素以右均比其大。對分割元素左...

線性時間選擇 TOP K

問題描述 找出乙個陣列中第k小的元素,時間複雜度為o n 解法 1.首先大家都會想到的解法是排序,之後找出第k個元素,但是排序的時間複雜度不符合要求,或者需要額外的空間。2.利用快排的思想,以樞紐 隨機得到 為界,將陣列分為2部分,一部分小於等於這個樞紐值,一部分大於這個樞紐值,與快排不同的是,我們...

線性時間選擇問題

將n個元素劃分成n 5組,每組5個元素,只可能有一組不是5個元素。再用氣泡排序法,將每組內的五個元素排好序,取出其中位數,共n 5個。然後遞迴呼叫select方法找出這n 5個數中的中位數。若n 5是偶數,就找其最大的數。以這個元素作為劃分標準。判斷k與n的位置,再進行下一步的劃分。以 8,31,6...