海量資料中找top K專題

2021-09-07 17:48:13 字數 1569 閱讀 6493

這種題目就是分治+堆排序。

為啥分治?因為數太多了,全部載入進記憶體不夠用,所以分配到多台機器中,或者多個檔案中,但具體分成多少份,視情況而定,只要保證滿足記憶體限制即可。什麼,如何分?hash(num)% numoffiles。

為啥堆排序?首先堆排序是一種選擇排序,比一般的選擇排序時間複雜度要低,額外的空間複雜度都是o(1)。因為我只要在每乙份中拿出最大的1000個即可,這裡用大頂堆還是小頂堆呢?

開始我覺得是大頂堆,我們不妨舉個例子:假設10億個數,分成若干組,每組假設1000000,我們所要做的,就是在這1000000的個數中,找出前1000。如果採用大頂堆,意味著我們需要構建1000000節點的乙個大樹,然後調整找出前1000,就是根嘛。但是你不覺得這個樹太大了嗎?而要是小頂堆呢?我只要構建乙個1000節點的樹即可,這樣我從剩餘元素中拿出來和根比較,如果比根小直接捨棄,如果比根大,替換根的位置,然後重新調整堆,這樣最後這1000個節點就是最大的。

最後把每乙份中的1000個最大的數合在一起找最終結果就夠了(可以繼續用堆排序查詢),有沒有覺得這個就是mapreduce的shuffle的思想,如果不了解建議看一下我的另一篇部落格:不同的是shuffle中合併排序採用的是歸併排序。

堆排序講解,請參考:

這道題和上道題本質相同,通常比較好的方案是分治+trie樹/hash+堆排序,即先將資料集按照hash方法分解成多個小資料集,然後使用trie樹或者hash統計每個數字的詞頻,之後用堆排序求出每個資料集**現頻率最高的前k個數,最後再合併求最終的top k。

我剛開始的想法是分治+排序,然後每個二分查詢,可是感覺還是複雜度蠻高的。

後來突然想到mysql資料庫中的索引,就想成給主鍵建立索引,然後查詢主鍵不就好了嗎?

參考innodb資料庫索引的思路,建立乙個主鍵索引,這裡不用建立輔助索引了,因為你只有主鍵,哈哈~然後索引通過b+樹進行儲存,為什麼採用b+樹,主要為了減少io次數,為啥不用b-樹(b樹),額,定義上好像說了,請看:

b+樹是b樹的乙個公升級版,相對於b樹來說b+樹更充分的利用了節點的空間,讓查詢速度更加穩定,其速度完全接近於二分法查詢。為什麼說b+樹查詢的效率要比b樹更高、更穩定;我們先看看兩者的區別:

(1)b+跟b樹不同b+樹的非葉子節點不儲存關鍵字記錄的指標,這樣使得b+樹每個節點所能儲存的關鍵字大大增加;

(2)b+樹葉子節點儲存了父節點的所有關鍵字和關鍵字記錄的指標,每個葉子節點的關鍵字從小到大鏈結;

(3)b+樹的根節點關鍵字數量和其子節點個數相等;

(4)b+的非葉子節點只進行資料索引,不會存實際的關鍵字記錄的指標,所有資料位址必須要到葉子節點才能獲取到,所以每次資料查詢的次數都一樣;

特點:在b樹的基礎上每個節點儲存的關鍵字數更多,樹的層級更少所以查詢資料更快,所有指關鍵字指標都存在葉子節點,所以每次查詢的次數都相同所以查詢速度更穩定;

具體參見:

這樣我們就可以通過索引在葉子節點查詢到我們的數字了。

參考:

海量資料 TopK問題

在海量資料中找出出現頻率最高的前k個數,或者從海量資料中找出最大的前k個數,這類問題通常被稱為topk問題。下面我們通過乙個簡單的例子來說明 假如面試官給你100w個資料,請找出其最大的前k個數,而且現在只有1m的空間?在32位作業系統中,預設乙個位元組為4個位元組,則有下列運算 needsize ...

海量資料topK問題

給你一億個資料,從中找出前k個大的資料。有兩種解決辦法。1.直接將資料從大到小排序,然後取前k個。但是由於資料的數量過於龐大,要開闢很大的空間,很浪費記憶體,所以這種方法不建議使用。2.用堆來解決。要找前k個大的資料,則將待找的元素的前k個元素建立大小為k的小根堆,小根堆的堆頂元素是這k個資料中最小...

海量資料處理 top K

區域性淘汰法 用乙個容器儲存前 10000個數,然後將剩餘的所有數字一一與容器內的最小數字相比,如果所有後續的元素都比容器內的 1000個數還小,那麼容器內的這 10000個數就是最大的 10000個數。如果某一後續元素比容器內的最小數字大,則刪掉容器內最小元素,並將該元素插入容器,最後遍歷完這1億...