海量資料處理問題知識點複習手冊

qqxx6661發表於2019-03-04

在這裡插入圖片描述

前言

本文快速回顧了常考的知識點,用作面試複習,事半功倍。

面試知識點複習手冊

通過以下兩種途徑檢視全複習手冊文章導航

本文參考

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

https://blog.csdn.net/v_july_v/article/details/6279498

重點:十七道海量資料處理面試題與Bit-map詳解

https://blog.csdn.net/v_july_v/article/details/6685962

有刪減,修改,補充額外增加內容

本作品採用知識共享署名-非商業性使用 4.0 國際許可協議進行許可。

-----正文開始-----

預備知識點

Bitmap和布隆過濾器(Bloom Filter)

https://blog.csdn.net/zdxiq000/article/details/57626464

Bitmap

我們只想知道某個元素出現過沒有。如果為每個所有可能的值分配1個bit,32bit的int所有可能取值需要記憶體空間為:

2^32bit=2^29Byte=512MB

但對於海量的、取值分佈很均勻的集合進行去重,Bitmap極大地壓縮了所需要的記憶體空間。於此同時,還額外地完成了對原始陣列的排序工作。缺點是,Bitmap對於每個元素只能記錄1bit資訊,如果還想完成額外的功能,恐怕只能靠犧牲更多的空間、時間來完成了。

Bloom Filter

如果說Bitmap對於每一個可能的整型值,通過直接定址的方式進行對映,相當於使用了一個雜湊函式,那布隆過濾器就是引入了k(k>1)個相互獨立的雜湊函式,保證在給定的空間、誤判率下,完成元素判重的過程。下圖中是k=3時的布隆過濾器。

在這裡插入圖片描述

那麼布隆過濾器的誤差有多少?我們假設所有雜湊函式雜湊足夠均勻,雜湊後落到Bitmap每個位置的概率均等。

在這裡插入圖片描述

若以m=16nm=16n計算,Bitmap集合的大小為238bit=235Byte=32GB238bit=235Byte=32GB,此時的ε≈0.0005。並且要知道,以上計算的都是誤差的上限。

布隆過濾器通過引入一定錯誤率,使得海量資料判重在可以接受的記憶體代價中得以實現。從上面的公式可以看出,隨著集合中的元素不斷輸入過濾器中(nn增大),誤差將越來越大。但是,當Bitmap的大小mm(指bit數)足夠大時,比如比所有可能出現的不重複元素個數還要大10倍以上時,錯誤概率是可以接受的。

這裡有一個google實現的布隆過濾器,我們來看看它的誤判率:

在這個實現中,Bitmap的集合m、輸入的原始數集合n、雜湊函式k的取值都是按照上面最優的方案選取的,預設情況下保證誤判率ε=0.5k<0.03≈0.55,因而此時k=5。

而還有一個很有趣的地方是,實際使用的卻並不是5個雜湊函式。實際進行對映時,而是分別使用了一個64bit雜湊函式的高、低32bit進行迴圈移位。註釋中包含著這個演算法的論文“Less Hashing, Same Performance: Building a Better Bloom Filter”,論文中指明其對過濾器效能沒有明顯影響。很明顯這個實現對於m>232時的支援並不好,因為當大於231−1的下標在演算法中並不能被對映到。

海量資料問題解題思路

參考:https://blog.csdn.net/luochoudan/article/details/53736752

個人將這些題分成了兩類:一類是容易寫程式碼實現的;另一類側重考察思路的。毫無疑問,後一種比較簡單,你只要記住它的應用場景、解決思路,並能在面試的過程中將它順利地表達出來,便能以不變應萬變。前一種,需要手寫程式碼,就必須要掌握一定的技巧,常見的解法有兩種,就是前面說過的堆排和快排的變形。

  • 堆排序:我認為不用變形,會原始堆排序就行。
  • 快排變形(找到最大的TopK): 當len(ary) - K == key or len(ary) - K == key + 1時就得到了最大的K個數。

注意點:

  • 分小檔案:hash後直接儲存原來的值,而不是將hash值分到各個檔案中。
  • 單位換算:一位元組8bit

經典題目:

序號對應於參考網頁:

https://blog.csdn.net/v_july_v/article/details/6685962

hash後將海量資料分到另外的小檔案中,分別處理,最後再歸併

1.2.3.4.7.8.11.13

經典例題:2

有10個檔案,每個檔案1G,每個檔案的每一行存放的都是使用者的query,每個檔案的query都可能重複。要求你按照query的頻度排序。

方案1:

順序讀取10個檔案,按照hash(query)%10的結果將query寫入到另外10個檔案(記為)中。這樣新生成的檔案每個的大小大約也1G(假設hash函式是隨機的)。 找一臺記憶體在2G左右的機器,依次對用hash_map(query, query_count)來統計每個query出現的次數。利用快速/堆/歸併排序按照出現次數進行排序。將排序好的query和對應的query_cout輸出到檔案中。這樣得到了10個排好序的檔案(,此處有誤,更正為b0,b1,b2,b9)。 對這10個檔案進行歸併排序(內排序與外排序相結合)。

方案2:

一般query的總量是有限的,只是重複的次數比較多而已,可能對於所有的query,一次性就可以加入到記憶體了。這樣,我們就可以採用trie樹/hash_map等直接來統計每個query出現的次數,然後按出現次數做快速/堆/歸併排序就可以了

bitmap直接對映

經典例題:5

在2.5億個整數中找出不重複的整數,記憶體不足以容納這2.5億個整數。

方案1:採用2-Bitmap(每個數分配2bit,00表示不存在,01表示出現一次,10表示多次,11無意義)進行,共需記憶體2^32*2bit=1GB記憶體,還可以接受。然後掃描這2.5億個整數,檢視Bitmap中相對應位,如果是00變01,01變10,10保持不變。所描完事後,檢視bitmap,把對應位是01的整數輸出即可。

方案2:也可採用上題類似的方法,進行劃分小檔案的方法。然後在小檔案中找出不重複的整數,並排序。然後再進行歸併,注意去除重複的元素。

最大最小堆

經典例題:6

海量資料分佈在100臺電腦中,想個辦法高效統計出這批資料的TOP10。

在每臺電腦上求出TOP10,可以採用包含10個元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。比如求TOP10大,我們首先取前10個元素調整成最小堆,如果發現,然後掃描後面的資料,並與堆頂元素比較,如果比堆頂元素大,那麼用該元素替換堆頂,然後再調整為最小堆。最後堆中的元素就是TOP10大。

桶排序

經典例題:15

給定n個實數,求著n個實數在實軸上向量2個數之間的最大差值,要求線性的時間演算法。

方案1:最先想到的方法就是先對這n個資料進行排序,然後一遍掃描即可確定相鄰的最大間隙。但該方法不能滿足線性時間的要求。故採取如下方法:

  1. 找到n個資料中最大和最小資料max和min。
  2. 用n-2個點等分割槽間[min, max],即將[min, max]等分為n-1個區間(前閉後開區間),將這些區間看作桶,編號為,且桶i 的上界和桶i+1的下屆相同,即每個桶的大小相同。每個桶的大小為:。實際上,這些桶的邊界構成了一個等差數列(首項為min,公差為),且認為將min放入第一個桶,將max放入第n-1個桶。
  3. 將n個數放入n-1個桶中:將每個元素x[i] 分配到某個桶(編號為index),其中(這括號裡多了個“+”),並求出分到每個桶的最大最小資料。
  4. 最大間隙:除最大最小資料max和min以外的n-2個資料放入n-1個桶中,由抽屜原理可知至少有一個桶是空的,又因為每個桶的大小相同,所以最大間隙不會在同一桶中出現,一定是某個桶的上界和氣候某個桶的下界之間隙,且該量筒之間的桶(即便好在該連個便好之間的桶)一定是空桶。也就是說,最大間隙在桶i的上界和桶j的下界之間產生j>=i+1。一遍掃描即可完成。

並查集

經典例題:16

TopK問題(注重程式碼實現)

經典例題:12

100w個數中找出最大的100個數。

方案1:採用區域性淘汰法。選取前100個元素,並排序,記為序列L。然後一次掃描剩餘的元素x,與排好序的100個元素中最小的元素比,如果比這個最小的要大,那麼把這個最小的元素刪除,並把x利用插入排序的思想,插入到序列L中。依次迴圈,知道掃描了所有的元素。複雜度為O(100w*100)。

方案2:採用快速排序的思想,每次分割之後只考慮比軸大的一部分,知道比軸大的一部分在比100多的時候,採用傳統排序演算法排序,取前100個。複雜度為O(100w100)。 方案3:在前面的題中,我們已經提到了,用一個含100個元素的最小堆完成。複雜度為O(100wlg100)。

字典樹Tire樹

經典例題:3.9.10

有一個1G大小的一個檔案,裡面每一行是一個詞,詞的大小不超過16位元組,記憶體限制大小是1M。返回頻數最高的100個詞。

方案1:順序讀檔案中,對於每個詞x,取,然後按照該值存到5000個小檔案(記為)中。這樣每個檔案大概是200k左右。如果其中的有的檔案超過了1M大小,還可以按照類似的方法繼續往下分,直到分解得到的小檔案的大小都不超過1M。對每個小檔案,統計每個檔案中出現的詞以及相應的頻率(可以採用trie樹/hash_map等),並取出出現頻率最大的100個詞(可以用含100個結點的最小堆),並把100詞及相應的頻率存入檔案,這樣又得到了5000個檔案。下一步就是把這5000個檔案進行歸併(類似與歸併排序)的過程了。

求中位數

經典例題:14

一共有N個機器,每個機器上有N個數。每個機器最多存O(N)個數並對它們操作。如何找到N^2個數中的中數?

方案1:先大體估計一下這些數的範圍,比如這裡假設這些數都是32位無符號整數(共有2^32個)。我們把0到2^32-1的整數劃分為N個範圍段,每個段包含(2^32)/N個整數。比如,第一個段位0到2^32/N-1,第二段為(2^32)/N到(2^32)/N-1,…,第N個段為(2^32)(N-1)/N到2^32-1。然後,掃描每個機器上的N個數,把屬於第一個區段的數放到第一個機器上,屬於第二個區段的數放到第二個機器上,…,屬於第N個區段的數放到第N個機器上。注意這個過程每個機器上儲存的數應該是O(N)的。下面我們依次統計每個機器上數的個數,一次累加,直到找到第k個機器,在該機器上累加的數大於或等於(N^2)/2,而在第k-1個機器上的累加數小於(N^2)/2,並把這個數記為x。那麼我們要找的中位數在第k個機器中,排在第(N^2)/2-x位。然後我們對第k個機器的數排序,並找出第(N^2)/2-x個數,即為所求的中位數的複雜度是O(N^2)的。

方案2:先對每臺機器上的數進行排序。排好序後,我們採用歸併排序的思想,將這N個機器上的數歸併起來得到最終的排序。找到第(N^2)/2個便是所求。複雜度是O(N^2*lgN^2)的。

補充題目:在10G的資料中找出中位數

不妨假設10G個整數是64bit的。 2G記憶體可以存放256M個64bit整數。 我們可以將64bit的整數空間平均分成256M個取值範圍,用2G的記憶體對每個取值範圍內出現整數個數進行統計。這樣遍歷一邊10G整數後,我們便知道中數在那個範圍內出現,以及這個範圍內總共出現了多少個整數。 如果中數所在範圍出現的整數比較少,我們就可以對這個範圍內的整數進行排序,找到中數。如果這個範圍內出現的整數比較多,我們還可以採用同樣的方法將此範圍再次分成多個更小的範圍(256M=2^28,所以最多需要3次就可以將此範圍縮小到1,也就找到了中數)。

補充的知識:

AVL樹 最早的平衡二叉樹之一。應用相對其他資料結構比較少。windows對程式地址空間的管理用到了avl樹。

紅黑樹 平衡二叉樹,廣泛用在c++的stl中。如map和set都是用紅黑樹實現的。

b/b+樹 用在磁碟檔案組織 資料索引和資料庫索引。

trie樹(字典樹): 用在統計和排序大量字串,如自動機。

參考:

http://www.cnblogs.com/huangxincheng/archive/2012/11/25/2788268.html

https://blog.csdn.net/hihozoo/article/details/51248823 (裡面Trie樹的應用寫的很好)

-----正文結束-----

更多精彩文章,請查閱我的部落格或關注我的公眾號:Rude3Knife

全複習手冊文章導航:通過以下兩種途徑檢視

知識點複習手冊文章推薦

關注我

我是蠻三刀把刀,目前為後臺開發工程師。主要關注後臺開發,網路安全,Python爬蟲等技術。

來微信和我聊聊:yangzd1102

Github:https://github.com/qqxx6661

原創部落格主要內容

  • 筆試面試複習知識點手冊
  • Leetcode演算法題解析(前150題)
  • 劍指offer演算法題解析
  • Python爬蟲相關技術分析和實戰
  • 後臺開發相關技術分析和實戰

同步更新以下部落格

1. Csdn

blog.csdn.net/qqxx6661

擁有專欄:

  • Leetcode題解(Java/Python)
  • Python爬蟲實戰
  • Java程式設計師知識點複習手冊

2. 知乎

www.zhihu.com/people/yang…

擁有專欄:

  • Java程式設計師面試複習手冊
  • LeetCode演算法題詳解與程式碼實現
  • 後臺開發實戰

3. 掘金

juejin.im/user/5b4801…

4. 簡書

www.jianshu.com/u/b5f225ca2…

個人公眾號:Rude3Knife

個人公眾號:Rude3Knife

如果文章對你有幫助,不妨收藏起來並轉發給您的朋友們~

相關文章