雜湊表**於陣列具有下標隨機訪問特性,理解這點非常重要。可以說雜湊表是由陣列進化來的。將輸入的鍵通過雜湊函式對映得出的value作為index去table中查詢,這便是雜湊的思想。
graph lr
a[鍵值key] -->|雜湊函式|b(結果value)
我們了解到為什麼雜湊表的查詢複雜度是o(1),因為key->value為計算過程,o(1),陣列支援隨機訪問,查詢也為o(1),所以雜湊表的查詢效率為o(1)。
我們可以很明確的看出,雜湊函式(即hash function)是至關重要的。雜湊函式具有的特點有:
第三點要求很難實現,這是由於雜湊衝突是幾乎不可避免的,我們來聊聊雜湊衝突。
像知名的hash演算法:md5,sha也無法完全避免雜湊衝突,常見的解決方法為兩類:開放定址和鍊錶法。
ⅰ ,開放定址
開放定址的思想是:如果出現了雜湊衝突,我們就重新探測乙個位置,將其插入。如何探測乙個新的位置呢?我們有幾種方法:
①,線性探測
如果出現衝突,則從當前位置往後挪,直到找到空閒位置。
優點缺點
簡單若元素過多,衝突概率會很大,查詢/插入/插入的效率急速降低
刪除元素不能直接刪除,要標記一下deleted
②,二次探測
它與第一種方法的區別是,線性探測挪動的步伐為1,而二次探測挪動的步伐為0,1,4,9,。。。。
③,雙重雜湊
我們不只使用乙個雜湊函式,我們使用一組雜湊函式,hash1,hash2,hash3,....
以上三種方法,不管用哪種,當裝載因子過大時,衝突的概率都會大大提高。
我們用裝載因子表示空位的剩餘。計算公式為:
裝載因子 = 填入的元素個數/table的長度
鍊錶法相對開放定址法,更加常用,更加簡明。在鍊錶法中,每個元素儲存的時一條鍊錶,所有雜湊值相同的元素,我們都放到對應的鍊錶中。
①,開放定址優劣
優點開放定址的資料都在雜湊表中,有效利用cpu快取,加快查詢,並且序列化簡單
缺點刪除資料比較麻煩,可能需要標記deleted,相比鍊錶法,衝突概率高,不能將裝載因子設計的太大,所以相比鍊錶法,更耗記憶體。4
②,鍊錶法優劣
優點記憶體利用率相對高,對大的裝載因子容忍,
缺點cpu快取不友好(由於有鍊錶)。
實際上我們可以在每個槽裡不存指向鍊錶的指標,而是存紅黑樹,跳表這種高效查詢的資料結構,有效避免雜湊碰撞攻擊(即使資料都擠在乙個槽,查詢效率也為o(logn))。
工業級的雜湊表,需要應對各種異常情況,避免雜湊衝突下效能急劇下降,抵抗雜湊碰撞攻擊。
ps:雜湊碰撞攻擊指的是惡意的使用者構造惡意的資料,使得所有資料經過雜湊函式之後,都進入了乙個bucket(slot,槽),再去查詢,這樣會大量消耗cpu資源,以此來做dos攻擊。要求:
不能太複雜,不然消耗cpu計算
生成的value盡量隨機且均勻分布。
合理利用關鍵字的特點,雜湊表的大小
例如,對於字串,我們可以用26進製求出值,再模長度
裝載因子過大,說明表中元素過多,空閒位置少,雜湊衝突的概率會很大,插入資料會多次定址(開放定址法)或槽中的鍊錶的很長(鍊錶法),導致查詢效率很低。
對於頻繁插入的動態雜湊表,當裝載因子超過某個閾值,需要進行擴容,重新申請記憶體空間,重新計算雜湊值,並搬移資料,o(n)的複雜度。
我們可以分批處理,先申請空間,將插入的資料直接插入新的雜湊表裡,然後舊的雜湊表裡的資料分批逐步的同步到新雜湊表,當查詢時可以先查新雜湊表,再查舊的。。
解決問題:觸發閾值擴容並搬移資料這個過程在資料量很大時效率是極低的,讓人崩潰
將任意長度的二進位制位對映到固定長度的二進位制位的對映規則,稱為雜湊演算法。value不能反推出key乙個優秀的雜湊演算法包括以下要求:
輸入的資料即使相差乙個bit,輸出的value也會相差很大
衝突概率盡可能小。『
演算法的執行效率要高,不占用過多計算資源。
我們著重了解雜湊演算法的應用。
最常用的安全加密演算法:md5,sha,des,aes。
為什麼可以用雜湊演算法做安全加密是由於key的向量空間是非常大的,利用窮舉的方法找到兩個雜湊值一樣的文字是幾乎不可能的。
拿一張,去判斷相簿中是否有這張,如何做呢?
對這張做雜湊運算,將得到的值進行去查,大大節省了時間。
雜湊表是雜湊函式的一種應用,區別是雜湊函式追求簡單,快速,對於加密並不重視。
如何實現乙個會話粘滯(session sticky)的負載均衡演算法?非常簡單,**通過雜湊演算法,對客戶端ip位址或會話id計算雜湊值,取模運算對映到相應的伺服器。
我們來看兩個非常常見的面試題:
ⅰ 大資料統計「搜尋關鍵字」出現的次數
description:我們有1t的記憶體,我們想快速統計每個關鍵字被搜尋的次數,怎麼做呢?我們有以下難點:
一台機器的記憶體,無法容納
只用一台機器,處理時間會很長
解決方法:
** 先對資料分片,採用多台機器,提高速度。**
具體思路:
我們用n臺機器並行處理,我們從搜尋記錄的日誌檔案中,依次讀取每個搜尋關鍵字,進行雜湊運算,跟n取模,得到值就是分配到的機器編號。
由此一來,雜湊值相同的搜尋關鍵字就被分配到了同一臺機器。
最後再將n臺機器的結果合併在一起。
這正是mapreduce的思想。
ⅱ 快速判斷是否在相簿中(相簿特別大)
如果我們對構建雜湊表,單台機器記憶體有限。
同樣,我們可以進行資料分片,採用多機處理。每台機器都有對應的雜湊表,我們去判斷的時候,先雜湊運算,取值模n得到機器號,再由相應的機器進行處理。當然,相應的機器可以構建雜湊表,由於資料分片了,記憶體是合適的。
面對海量資料,為了提高讀寫能力,一般用分布式方式儲存資料。
跟前面的思路類似,資料分片,雜湊運算獲得機器號,然後去相應的機器做查詢。
問題來了,假如快取機器不夠了,需要做擴容怎麼辦?麻煩來了,簡單的增加機器並不可取。比如本來10臺機器,那麼15被對映到5號機器,我們增加兩台,那麼15會被對映到3號機器。也就是說此時快取失效了(需要搬移資料到正確的機器上),會直接向資料庫索要資料,會壓垮資料庫。
一致性雜湊就是解決這個問題的,可以避免大量的資料搬移。
演算法學習 雜湊表
雜湊表 hash table,也叫雜湊表 是根據鍵 key 而直接訪問在記憶體儲存位置的資料結構。也就是說,它通過計算乙個關於鍵值的函式,將所需查詢的資料對映到表中乙個位置來訪問記錄,這加快了查詢速度。這個對映函式稱做雜湊函式,存放記錄的陣列稱做雜湊表。雜湊函式 hashfunction 若關鍵字為...
演算法學習 雜湊表及雜湊查詢
基於樹等的查詢方法,都是通過一系列對比來查詢的,查詢效率由比較一次所縮小的查詢範圍決定。而理想的查詢情況是直接根據關鍵碼得到其對應的資料元素位置。原理 將待儲存元素經過某一函式特定轉換為乙個值,將這個值作為位址,將這個待儲存元素存入這個位址中。當要查詢時,則將待查詢的元素經過同一轉換函式得到乙個轉換...
演算法學習 雜湊表應用
hash演算法就是一種壓縮對映,壓縮到有鍊表頭函式組成的固定長度陣列中。上實際例子 例1 100萬條簡訊,有重複,以文字形式儲存,一行一條。找出重複最少的前十條。解法 雜湊表 推排序。步驟一 統計重複次數,建立資料節點 struct hashnode node hash函式 int hashfuc ...