轉於
1、最容易想到的方法是將資料全部排序。該方法並不高效,因為題目的目的是尋找出最大的10000個數即可,而排序卻是將所有的元素都排序了,做了很多的無用功。
2、區域性淘汰法。用乙個容器儲存前10000個數,然後將剩餘的所有數字一一與容器內的最小數字相比,如果所有後續的元素都比容器內的10000個數還小,那麼容器內這個10000個數就是最大10000個數。如果某一後續元素比容器內最小數字大,則刪掉容器內最小元素,並將該元素插入容器,最後遍歷完這1億個數,得到的結果容器中儲存的數即為最終結果了。此時的時間複雜度為o(n+m^2),其中m為容器的大小。
這個容器可以用(小頂堆)最小堆來實現。我們知道完全二叉樹有幾個非常重要的特性,就是假如該二叉樹中總共有n個節點,那麼該二叉樹的深度就是log2n,對於小頂堆來說移動根元素到 底部或者移動底部元素到根部只需要log2n,相比n來說時間複雜度優化太多了(1億的logn值是26-27的乙個浮點數)。基本的思路就是先從檔案中取出1000個元素構建乙個小頂堆陣列k,然後依次對剩下的100億-1000個數字進行遍歷m,如果m大於小頂堆的根元素,即k[0],那麼用m取代k[0],對新的陣列進行重新構建組成乙個新的小頂堆。這個演算法的時間複雜度是o((100億-1000)log(1000)),即o((n-m)logm),空間複雜度是m
這個演算法優點是效能尚可,空間複雜度低,io讀取比較頻繁,對系統壓力大。
3、第三種方法是分治法,即大資料裡最常用的mapreduce。
a、將100億個資料分為1000個大分割槽,每個區1000萬個資料
b、每個大分割槽再細分成100個小分割槽。總共就有1000*100=10萬個分割槽
c、計算每個小分割槽上最大的1000個數。
為什麼要找出每個分割槽上最大的1000個數?舉個例子說明,全校高一有100個班,我想找出全校前10名的同學,很傻的辦法就是,把高一100個班的同學成績都取出來,作比較,這個比較資料量太大了。應該很容易想到,班裡的第11名,不可能是全校的前10名。也就是說,不是班裡的前10名,就不可能是全校的前10名。因此,只需要把每個班裡的前10取出來,作比較就行了,這樣比較的資料量就大大地減少了。我們要找的是100億中的最大1000個數,所以每個分割槽中的第1001個數一定不可能是所有資料中的前1000個。
d、合併每個大分割槽細分出來的小分割槽。每個大分割槽有100個小分割槽,我們已經找出了每個小分割槽的前1000個數。將這100個分割槽的1000*100個數合併,找出每個大分割槽的前1000個數。
e、合併大分割槽。我們有1000個大分割槽,上一步已找出每個大分割槽的前1000個數。我們將這1000*1000個數合併,找出前1000.這1000個數就是所有資料中最大的1000個數。
(a、b、c為map階段,d、e為reduce階段)
4、hash法。如果這1億個書裡面有很多重複的數,先通過hash法,把這1億個數字去重複,這樣如果重複率很高的話,會減少很大的記憶體用量,從而縮小運算空間,然後通過分治法或最小堆法查詢最大的10000個數。
對於海量資料處理,思路基本上是:必須分塊處理,然後再合併起來。
100億資料找出最大的1000個數字
這是網際網路領域乙個比較經典的演算法問題 top k 如何在巨大的資料中找出最大,或者訪問量最高的前10個,前100個或者前1000個資料。比如在2億使用者記錄中找出信用等級最高的,在上億個搜尋詞彙中找出被搜尋次數最高的10個關鍵字。前提是資料儲存在檔案中 一般遇到這個問題,第一反應會想到排序,但是...
100億個整數,找出中位數
100億個整數,記憶體足夠,如何找到中位數?記憶體不足,如何找到中位數?1 當記憶體足夠時 採用快排,找到第n大的數。隨機選取乙個數,將比它小的元素放在它左邊,比它大的元素放在右邊 如果它恰好在中位數的位置,那麼它就是中位數,直接返回 如果小於它的數超過一半,那麼中位數一定在左半邊,遞迴到左邊處理 ...
10億資料中取最大的100個資料
思路1 利用堆排序實現 1 取前m個元素 例如m 100 建立乙個小頂堆。保持乙個小頂堆得性質的步驟,執行時間為o lgm 建立乙個小頂堆執行時間為m o lgm o m lgm 2 順序讀取後續元素,直到結束。每次讀取乙個元素,如果該元素比堆頂元素小,直接丟棄。如果大於堆頂元素,則用該元素替換堆頂...