資料排序之TopK問題

2021-07-12 03:12:17 字數 2210 閱讀 3933

前言】在大規模資料處理中,常遇到的一類問題是,在海量資料中找出出現頻率最高的前k個數,或者從海量資料中找出最大的前k個數,這類問題通常稱為「topk」問題

解決思路

針對topk類問題,通常比較好的方案是【分治+trie樹/hash+小頂堆】,即先將資料集按照hash演算法分解成多個小資料集,然後使用trie樹或者hash表統計每個小資料集中的query詞頻,之後用小頂堆求出每個資料集中出頻率最高的前k個數,最後在所有top k中求出最終的top k。

實際上,最優的解決方案應該是最符合實際設計需求的方案,在實際應用中,可能有足夠大的記憶體,那麼直接將資料扔到記憶體中一次性處理即可,也可能機器有多個核,這樣可以採用多執行緒處理整個資料集。

解決】在得到資料後,如何對獲得的資料進行topk排序呢。下面簡單介紹幾種常見方法。

基於partition(分割槽)解決topk min的問題:根據陣列的第k個數字來調整,使得比第k個數小的都在陣列的左邊,比第k個資料大的所有數字在陣列的右邊。

/**

* 最小的k個數,o(n)解法,需要修改原陣列

* @param a

* @param n

* @param b

* @param k

*/public void topkmin(int a,int n,int b,int k)

for(int i=0;i=pivot)

right--;

if(left

複雜度分析:先用hash表統計每個query出現的次數,o(n);然後第二步、採用堆資料結構找出top 10,n*o(logk)。所以,我們最終的時間複雜度是:o(n) + *o(n1*logk)。(n為資料總數,n1為不重元素個數)。

@test

public void testbuildminheap();

int k=3;

int topk=new int[k];

for(int i=0;iroot)

} //buildminheap(a,a.length);

system.out.println(arrays.tostring(topk));

} public void heapfiy(int a,int i,int len)

}

基於優先順序佇列來實現的topk問題:實現comparator介面,使得佇列元素按照公升序/降序排序,維護乙個長度為k的陣列,把佇列的元素出隊放到陣列中即可。

/*

隊尾    

|1        |3

|2        |2           

|3        |1

隊頭降序      公升序

*/

public static int topklargest(int input, int k) else if(o1 > o2) else

}});

for (int i : input)

int out = new int[k];

for (int i = 0; i < out.length; i++)

return out;

} public static int topksmallest(int input, int k) else if(o1 > o2) else

}});

for (int i : input)

int out = new int[k];

for (int i = 0; i < out.length; i++)

return out;

} public static void main(string args) , 3);

system.out.print("largest: ");

for (int o : out)

out = topksmallest(new int , 3);

system.out.println();

system.out.print("largest: ");

for (int o : out)

}

【參考資料】

《十道海量資料處理面試題與十個方法大總結》:

Top K問題 基於快速排序

p為待查詢陣列,l,r分別為陣列下標,k表示第k大數 public intfindkth int p,int l,int r,int k 一次快速排序 以p l 為比較物件,比p l 大或等於的在其左邊,否則在其右邊 public intquicksort int p int l,int r whi...

堆排序與topK問題

找出乙個有10億數字陣列中,前k個最大值 第一步 hash去重 解法1 劃分法 def partition l,left,right low left if left right key l left high right while low high while low high and l hi...

堆排序 TOPK問題 C

現在有n個數,設計演算法得到前k大的數。k 首先從原列表擷取前k個元素,組成乙個新列表。然後將這個新列表構建成乙個小根堆,那麼根就新列表中最小的數。接著繼續從原列表取出k以後的元素,和小根堆根比對,如果比根小,那麼肯定不屬於前k大的數,如果比根大,替換根,然後做一次向下調整,根重新變成新列表最小的數...