1. 程式人生 > >Java程式設計師面試寶典筆記記錄(終)-第9章海量資料部分筆記

Java程式設計師面試寶典筆記記錄(終)-第9章海量資料部分筆記

前言

  本次博文對何昊出版的《java程式設計師面試寶典》的第9章海量資料部分的概括筆記,刪除部分內容,是本系列筆記部落格的最後一個博文。

相關知識

Hash法

  對映關係,給定資料元素,關鍵字是key,按照確定雜湊函式計算hash(key),然後該值作為關鍵字key對應元素的儲存位置,再進行資料插入和檢索。

  雜湊函式是將任意長度資訊壓縮為固定長度資訊摘要函式。

  散列表具有固定大小陣列,表長(陣列大小)為質數。雜湊函式是關鍵字與儲存地址間對映關係,不能保證一一對應,會發生hash衝突,即兩個關鍵幀不同丹對映同一儲存地址。

  hash函式具備特點:運算儘量簡單;值域必須在散列表範圍;儘可能減少衝突;

(1)直接定址

取關鍵字或關鍵字某個線性函式為雜湊地址,即h(key)=key或h(key)=a*key+b,a和b均為整型常數。

  時間複雜度O(1)\mathcal{O(1)},空間複雜度O(n)\mathcal{O(n)}

  不會產生衝突,因為沒有壓縮映像,關鍵字集合大,這種方式不可取。

(2)取模法

取合適正整數,hash(key)=key mod p。p是比較大素數比較好,一般取TableSize,即散列表長。

(3)數字分析法

  關鍵字是d位以r為基的數(例如10為基的十進位制),且共有n個關鍵幀,則關鍵幀的每個位可能有r個不同的數符(即0,1,2,…,9),但這r個數符在各個位上出現的頻率不一定相同,可能在某些位上分佈比較均勻,即每個數符出現的次數接近於n

/rn/r,而另一些位上分佈不均勻。因此取其中分佈均勻的那些位組成新數,用作雜湊地址。

  方法直觀簡單,但需要預先知道每個關鍵字情況,限制使用範圍。

(6)摺疊法

將關鍵字分為位數為1的幾個部分(最後一部分的位數可能小於1),然後把各部分按位對齊進行相加,將所得的和捨棄進位,留下 tt 位作為雜湊地址。當關鍵字位數很多,而且關鍵字中每位上數字分佈比較均勻,採用摺疊法合適。

(5)平方取中法

將關鍵字進行平方運算,然後從結果中間取出若干位(位數與雜湊地址的位數相同),將其作為雜湊地址,具體取幾位,由散列表表長決定。

(6)除留餘數法

取關鍵字除以某個數p(p不大於散列表長度)的餘數作為雜湊地址,H

ash(key)=key%pHash(key)=key\%p

p值很重要,一般小於表長,且接近或等於。一般是選質數,可以是不包含小於20質因子的合數。

(7)隨機數法

hash(key)=random(key)當關鍵字長度不相等,採用此法。

  衝突難以避免,解決hash衝突主要是當一個關鍵字對映後的地址若已有關鍵字則為該關鍵字重新尋找新的儲存地址。

(1)開放地址法

地址發生衝突,hash表再按照某種方法繼續探測其他開放地址,直到找到空閒地址為止。

Hi(key)=(H(key)+di)modm(i=1,2,...,k(k<=m1))H_i(key)=(H(key)+d_i) mod \quad m (i=1,2,...,k(k<=m-1))

其中,H(key)H(key)為關鍵字key的直接雜湊地址,mm為散列表的長度,did_i為每次再探測的地址增量

  該方式先找到直接H(key),若該地址已有其他關鍵字,則繼續檢視地址為[H(key)+di][H(key)+d_i]的儲存地址,判斷其是否為空。如此反覆,直到找到空閒的儲存地址為止,然後將關鍵幀key存放到該地址。

did_i的取法

  1)di=1,2,3,...,m1d_i=1,2,3,...,m-1,稱為線性探測再雜湊

  2)di=12,12,22,22,...,k2(k<=m/2)d_i=12,-12,22,-22,...,-k2(k<=m/2),稱為二次探測再雜湊

  3)di=d_i=偽隨機序列,稱為偽隨機再雜湊

  利用此法解決衝突的散列表,刪除元素不能直接刪除(會影響其他相同雜湊地址元素),採用特殊標記表示已被刪除。

(2)鏈地址法

若散列表空間為[0,m1][0,m-1],則設定一個由m個指標組成的一維陣列CH[m]CH[m],好在尋找關鍵字雜湊地址過程中,所有雜湊地址為ii的資料元素都插入到頭指標為CH[i]CH[i]的連結串列中。

  適用於衝突嚴重情況。

(3)再雜湊

發生衝突,使用第二個、第三個、雜湊函式計算地址,直到無衝突為止。

  計算時間會大幅增加

(4)建立一個公共溢位區

假設雜湊函式值域[0,m1][0,m-1],設立儲存空間向量OverTable[0,...,v]OverTable[0,...,v]用以儲存發生衝突記錄

  hash主要用來“快速存取”,在O(1)\mathcal{O}(1)複雜度可以查到目標元素,或判其是否存在。

  hash資料結構中的資料對外是雜亂無序,因此具體儲存位置及各個儲存元素之間的相互關係無法得知,但可在常數時間判斷元素位姿和存在與否。

  hash法一般可以快速存取和統計某些資料,將大量資料分類。

Bit-map法

  使用陣列表示某些元素存在與否。適用於海量資料快速查詢,判重,刪除等。

  該法生成一個N位長串,每位以“1”或“0”表示需要排序的集合中的數。

  時間複雜度O(n)\mathcal{O(n)},以空間換時間,要求資料狀態不多。

  適用於資料量大,判斷是否重複問題或集合某資料是否存在。

Bloom Filter法

  以犧牲正確率,一種空間小和時間效率都很高的隨機資料結構,用來檢測元素是否屬於集合。適用於低錯誤率可以容忍的場合。(不屬於是絕對正確,屬於可能是錯誤)

  將位資料與Hash函式聯合使用。Bloom Filter是包含m位的位陣列,每位都是0。定義k不同的hash函式,每個函式可以將集合元素對映到位陣列某一位。當集合插入元素,根據k個hash函式可以得到位陣列k個位,將這些位設定為1。

  如果查詢某元素屬於集合,則根據k個hash函式得到位陣列k個位,檢視k個位中值,有的位不為1,則元素肯定不在集合中;若全為1,則可能存在。在插入其他元素,可能把這些元素位置設為1,產生錯誤。

  難點在於如何根據輸入元素個數n確定位陣列m的大小以及hash函式。當hash函式個數k=(ln2)(m/2)k=(\ln2)*(m/2)時錯誤率最小,在錯誤率不大於E的情況下,m至少等於nlog(1/E)n*\log(1/E)才能表示任意n個元素的集合。但m還應更大,因為至少保證位數組裡至少一半為0,所以m應該nlg(1/E)lg(e)\ge n*\lg(1/E)*\lg (e)。大概就是nlg(1/E)n*\lg(1/E)的1.44倍,lg表示以2為底的對數。

  通常單元素長度有很多bit,使用該法在記憶體通常是節省的。

  該法優點在空間效率和時間效率。在插入和查詢都是常量時間,不儲存元素本身具有良好安全,但都以犧牲正確率為代價。當插入元素越多,判斷“元素輸入該集合”概率越大。另外只能插入元素而不能刪除元素,因為多個元素雜湊結果可能共用同一位。如果刪除,會影響多個元素檢測。

  使用該法實現資料字典、進行資料判重和集合求交集。

  CBF和SBF是該方法擴充套件,前者在每位擴充套件counter用以支援元素刪除,後者與集合元素次數關聯,使用counter最小值近似表示元素的出現頻率。

資料庫優化法

  (1)優秀資料庫管理工具(DB2,MySQL等)

  (2)資料分割槽。

  (3)索引。

  (4)快取機制

  (5)加大虛存

  (6)分批處理(分而治之,類似MapReduce),利用小資料量

  (7)使用臨時表和中間表。

  (8)優化查詢語句

  (9)使用檢視

  (10)使用儲存過程

  (11)用排序來取代非順序存取

  (12)使用取樣資料進行資料探勘

倒排索引法

  指按照關鍵字建立索引。又稱為反向索引,置入檔案或反向檔案。

  被用來儲存在全文搜尋下某個單詞在一個文件中的儲存位置對映,它是文件檢索系統中最常用的資料結構,有兩種不同反向索引形式。第一種形式是一條記錄的水平反向索引(或反向檔案索引)包含每個引用單詞的文件的列表;第二種形式是一個單詞的水平反向索引(或完全反向索引)又包含每個單詞在一個文件中的位置。第二種形式提供了更多相容性(如短語搜尋),但需要更多時間和空間建立。

  一般採用矩陣方式儲存來儲存會浪費大量空間。

  倒排索引比採用矩陣方式節省很多空間。

  正向索引用來儲存每個文件的單詞列表。正向索引查詢往往滿足每個文件有序頻繁的全文查詢和每個單詞在校驗文件中的驗證這樣查詢。在正向索引中,文件佔據了中心位置,每個文件指向一個它所包含索引項。

  文件指向它包含的單詞,而反向索引則單詞指向包含它的文件。

  倒排索引優點,處理複雜多關鍵字查詢,可在倒排表完成查詢並交邏輯,得到結果對記錄進行存取,這樣把記錄查詢轉換為地址集合運算,而不必對每個記錄隨機存取,故而提高效率。

外排序法

  當待排序的物件數目特別多,在記憶體中不能一次處理,必須把它們以檔案的形式存放於外存,排序時再把它們一部分一部分地調入記憶體進行處理,這種方式就是外排序。

  大檔案排序,待排序記錄儲存在外儲存器說,帶排序檔案無法一次裝入記憶體。需要在記憶體和外部儲存器之間多次資料交換,以達到對整個檔案進行排序目的。一般採用歸併排序等方式實現外排序。

  分兩步,第一步生成若干歸併段(順串),也稱為檔案預處理,把含有n個記錄的檔案,按記憶體大小劃分為若干長度為L的子檔案,然後分別把子檔案調入記憶體,採用有效的內排序方法排序後送回記憶體。

  第二步,進行多路歸併,即對這初始歸併段進行多便歸併,並使得有序的歸併段逐漸擴大,最後在外存上形成整個檔案的單一歸併段,也就是完成了檔案的外排序。

  外排序適用於大資料的排序以及去重複,但外排序也存在很大缺陷,會耗大量IO,效率不高。

Trie樹

  字典樹或鍵樹,一種快速字串檢索多叉樹結構,利用字串的公共字首減少時空開銷,以空間換時間,達到提高程式效率目的。

  典型用於統計和排序大量字串(不限於字串),用於文字詞頻統計。

  能最大限度減少無謂字串比較,查詢效率比散列表高。

三個基本特性  (1) 根節點不包含字元,除根節點外每個節點只包含一個字元。   (2)從根節點到某一節點,經過路徑的字元連線即為結點對應字串;   (3)每個結點的所有子結點包含字元都不相同。

若是大量字串無公共字首,則耗費記憶體。

適用於資料量大,重複多,資料種類小可放入記憶體情況。

雙層捅

  演算法思想,分而治之。因元素範圍大,不能直接定址,所以多次劃分,逐步確定範圍,最後在一個可接受範圍進行。

top K問題

  找出頻率最高前K個數,最大的前K數。

  最好是分冶+Trie樹/hash+小頂端

  將資料集按照hash方法分解為多個小資料集,然後使用Trie樹或hash統計對每個小資料集的query詞頻,然後用小頂端求出每個資料集頻率最高的前K個數,最好在所有topK中求出最終的topK。

重複問題

  一般用點陣圖實現。

排序問題

  (1)資料庫排序法

  (2)分冶法。

  (3)點陣圖法

結語

  本系列筆記部落格的最後一個博文,是對何昊出版的《java程式設計師面試寶典》的第9章海量資料部分的概括筆記,刪除部分內容(比如堆,MapReduce等),有需可以購買該書或者查詢該處內容,我覺得這兩個地方比較簡單易懂就不整理了。