題目描述
有一個 1GB 大小的文件,文件里每一行是一個詞,每個詞的大小不超過 16B,內存大小限制是 1MB,要求返回頻數最高的 100 個詞(Top 100)。
解答思路
由於內存限制,我們依然無法直接將大文件的所有詞一次讀到內存中。因此,同樣可以采用分治策略,把一個大文件分解成多個小文件,保證每個文件的大小小於 1MB,進而直接將單個小文件讀取到內存中進行處理。
思路如下:
首先遍歷大文件,對遍歷到的每個詞x,執行 hash(x) % 5000
,將結果為 i 的詞存放到文件 ai 中。遍歷結束后,我們可以得到 5000 個小文件。每個小文件的大小為 200KB 左右。如果有的小文件大小仍然超過 1MB,則采用同樣的方式繼續進行分解。
接着統計每個小文件中出現頻數最高的 100 個詞。最簡單的方式是使用 HashMap 來實現。其中 key 為詞,value 為該詞出現的頻率。具體方法是:對於遍歷到的詞 x,如果在 map 中不存在,則執行 map.put(x, 1)
;若存在,則執行 map.put(x, map.get(x)+1)
,將該詞頻數加 1。
上面我們統計了每個小文件單詞出現的頻數。接下來,我們可以通過維護一個小頂堆來找出所有詞中出現頻數最高的 100 個。具體方法是:依次遍歷每個小文件,構建一個小頂堆,堆大小為 100。如果遍歷到的詞的出現次數大於堆頂詞的出現次數,則用新詞替換堆頂的詞,然后重新調整為小頂堆,遍歷結束后,小頂堆上的詞就是出現頻數最高的 100 個詞。
方法總結
- 分而治之,進行哈希取余,文件分割;
- 使用 HashMap 統計頻數;
- 求解最大的 TopN 個,用小頂堆;求解最小的 TopN 個,用大頂堆。
題型變化——》
題目描述
現有海量日志數據保存在一個超大文件中,該文件無法直接讀入內存,要求從中提取某天訪問百度次數最多的那個 IP。
解答思路
這道題只關心某一天訪問百度最多的 IP,因此,可以首先對文件進行一次遍歷,把這一天訪問百度 IP 的相關信息記錄到一個單獨的大文件中。接下來采用的方法與上一題一樣,大致就是先對 IP 進行哈希映射,接着使用 HashMap 統計重復 IP 的次數,最后計算出重復次數最多的 IP。
注:這里只需要找出出現次數最多的 IP,可以不必使用堆,直接用一個變量 max 即可。
方法總結
- 分而治之,進行哈希取余;
- 使用 HashMap 統計頻數;
- 求解最大的 TopN 個,用小頂堆;求解最小的 TopN 個,用大頂堆。