問題描述:給定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**如下,**寫法都比較通用,讀者可以很容易轉換為其他語言實現:
1view codeimport
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 }
輸出結果為:
陣列為: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...