HASH碰撞問題一直沒真正搞懂?這下不用慌了

我是架構精進之路,點擊上方「關注」,堅持天天爲你分享技術乾貨,私信我回復「01」,送你一份程序員成長進階大禮包。程序員

 

HASH算法介紹

散列函數(英語:Hash function)又稱散列算法、哈希函數,是一種從任何一種數據中建立小的數字「指紋」的方法。散列函數把消息或數據壓縮成摘要,使得數據量變小,將數據的格式固定下來。該函數將數據打亂混合,從新建立一個叫作散列值(hash values,hash codes,hash sums,或hashes)的指紋。散列值一般用一個短的隨機字母和數字組成的字符串來表明。算法

哈希表就是一種以 鍵-值(key-indexed) 存儲數據的結構,咱們只要輸入待查找的值即key,便可查找到其對應的值。編程

哈希的思路很簡單,若是全部的鍵都是整數,那麼就可使用一個簡單的無序數組來實現:將鍵做爲索引,值即爲其對應的值,這樣就能夠快速訪問任意鍵的值。這是對於簡單的鍵的狀況,咱們將其擴展到能夠處理更加複雜的類型的鍵。數組

Hash算法能夠將一個數據轉換爲一個標誌,這個標誌和源數據的每個字節都有十分緊密的關係。Hash算法還具備一個特色,就是很難找到逆向規律。安全

Hash算法也被稱爲散列算法,Hash算法雖然被稱爲算法,但實際上它更像是一種思想。Hash算法沒有一個固定的公式,只要符合散列思想的算法均可以被稱爲是Hash算法。服務器

經常使用HASH算法

常見Hash算法介紹:微信

1)MD4數據結構

MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年設計的,MD 是 Message Digest(消息摘要) 的縮寫。它適用在32位字長的處理器上用高速軟件實現——它是基於 32位操做數地位操做來實現的。架構

2)MD5負載均衡

MD5(RFC 1321)是 Rivest 於1991年對MD4的改進版本。它對輸入仍以512位分組,其輸出是4個32位字的級聯,與 MD4 相同。MD5比MD4來得複雜,而且速度較之要慢一點,但更安全,在抗分析和抗差分方面表現更好。

3)SHA-1及其餘

SHA1是由NIST NSA設計爲同DSA一塊兒使用的,它對長度小於264的輸入,產生長度爲160bit的散列值,所以抗窮舉(brute-force)性更好。SHA-1 設計師基於和MD4相同原理,而且模仿了該算法。

HASH 算法的性質

全部散列函數都有以下一個基本特性:若是兩個散列值是不相同的(根據同一函數),那麼這兩個散列值的原始輸入也是不相同的。這個特性是散列函數具備肯定性的結果,具備這種性質的散列函數稱爲單向散列函數。

散列表,它是基於快速存取的角度設計的,也是一種典型的「空間換時間」的作法。顧名思義,該數據結構能夠理解爲一個線性表,可是其中的元素不是緊密排列的,而是可能存在空隙。

好比咱們存儲70個元素,但咱們可能爲這70個元素申請了100個元素的空間。70/100=0.7,這個數字稱爲負載因子。

咱們之因此這樣作,也是爲了「快速存取」的目的。

咱們基於一種結果儘量隨機平均分佈的固定函數H爲每一個元素安排存儲位置,這樣就能夠避免遍歷性質的線性搜索,以達到快速存取。

這相似於70我的去一個有100個椅子的飯店吃飯。散列函數的計算結果是一個存儲單位地址,每一個存儲單位稱爲「桶」。設一個散列表有m個桶,則散列函數的值域應爲[0,m-1]。

哈希碰撞是什麼?

若是不一樣的輸入經哈希映射獲得了同一個哈希值,就發生了"哈希碰撞"(collision)。

假設hash表的大小爲11(即有11個槽),如今要把一串數據存到表裏:1,2,3,4,5,6...

簡單計算一下:hash(1) = 5, 即數據1應該放在hash表的第5個槽裏;hash(2)=1,因此數據2應該放在hash表的第1個槽裏;hash(3)=1,也就是說,數據3也應該放在hash表的第1個槽裏——因而就形成了碰撞(也稱爲衝突)。

Hash衝突經常使用解決方案

經常使用的Hash衝突解決方法有如下幾種:

1. 開放尋址法

這種方法也稱再散列法,其基本思想是:當關鍵字key的哈希地址p=H(key)出現衝突時,以p爲基礎,產生另外一個哈希地址p1,若是p1仍然衝突,再以p爲基礎,產生另外一個哈希地址p2,…,直到找出一個不衝突的哈希地址pi ,將相應元素存入其中。這種方法有一個通用的再散列函數形式:

Hi=(H(key)+di)% m i=1,2,…,n

其中H(key)爲哈希函數,m 爲表長,di稱爲增量序列。增量序列的取值方式不一樣,相應的再散列方式也不一樣。主要有如下三種:

  • 線性探測再散列

dii=1,2,3,…,m-1

這種方法的特色是:衝突發生時,順序查看錶中下一單元,直到找出一個空單元或查遍全表。

  • 二次探測再散列

di=12,-12,22,-22,…,k2,-k2 ( k<=m/2 )

這種方法的特色是:衝突發生時,在表的左右進行跳躍式探測,比較靈活。

  • 僞隨機探測再散列

di=僞隨機數序列。

具體實現時,應創建一個僞隨機數發生器,(如i=(i+p) % m),並給定一個隨機數作起點。

舉個實際應用例子

例如,已知哈希表長度m=11,哈希函數爲:

H(key)= key % 11

則H(47)=3,H(26)=4,H(60)=5,假設下一個關鍵字爲69,則H(69)=3,與47衝突。

case1:若是用線性探測再散列處理衝突

下一個哈希地址爲

H1=(3 + 1)% 11 = 4

仍然衝突,再找下一個哈希地址爲

H2=(3 + 2)% 11 = 5

仍是衝突,繼續找下一個哈希地址爲

H3=(3 + 3)% 11 = 6

此時再也不衝突,將69填入5號單元。

case2:二次探測再散列處理衝突

下一個哈希地址爲:

H1=(3 + 12)% 11 = 4

仍然衝突,再找下一個哈希地址爲

H2=(3 - 12)% 11 = 2

此時再也不衝突,將69填入2號單元。

case3:用僞隨機探測再散列處理衝突

且僞隨機數序列爲:2,5,9,……..,則下一個哈希地址爲

H1=(3 + 2)% 11 = 5

仍然衝突,再找下一個哈希地址爲

H2=(3 + 5)% 11 = 8

此時再也不衝突,將69填入8號單元。

2.再哈希法(Rehash)

這種方法是同時構造多個不一樣的哈希函數:

Hi=RH1(key) i=1,2,…,k

當哈希地址Hi=RH1(key)發生衝突時,再計算Hi=RH2(key)……,直到衝突再也不產生。這種方法不易產生彙集,但增長了計算時間。

3.鏈地址法(拉鍊法)

這種方法的基本思想是將全部哈希地址爲i的元素構成一個稱爲同義詞鏈的單鏈表,並將單鏈表的頭指針存在哈希表的第i個單元中,於是查找、插入和刪除主要在同義詞鏈中進行。鏈地址法適用於常常進行插入和刪除的狀況。

鏈地址法優缺點分析:

  • 優勢

1)拉鍊法處理衝突簡單,且無堆積現象,即非同義詞決不會發生衝突,所以平均查找長度較短;

2)因爲拉鍊法中各鏈表上的結點空間是動態申請的,故它更適合於造表前沒法肯定表長的狀況;

3)開放定址法爲減小衝突,要求裝填因子α較小,故當結點規模較大時會浪費不少空間。而拉鍊法中可取α≥1,且結點較大時,拉鍊法中增長的指針域可忽略不計,所以節省空間;

4)在用拉鍊法構造的散列表中,刪除結點的操做易於實現。只要簡單地刪去鏈表上相應的結點便可。

而對開放地址法構造的散列表,空地址單元(即開放地址)都是查找失敗的條件,刪除結點不能簡單地將被刪結點的空間置爲空,不然將截斷在它以後填入散列表的同義詞結點的查找路徑。只能在被刪結點上作刪除標記,而不能真正刪除結點。

  • 缺點

拉鍊法的缺點是:

指針須要額外的空間,故當結點規模較小時,開放定址法較爲節省空間,而若將節省的指針空間用來擴大散列表的規模,可以使裝填因子變小,這又減小了開放定址法中的衝突,從而提升平均查找速度。

 

Hash算法用途

1.數據校驗

上面說到的md5就是其中的一個, 好像還有一個什麼SHA, 不過我不知道, 也就不展開探討了.

md5能夠將一個文件通過計算轉換成一個指定長度的字符串, 能夠防止文件被篡改, 可是經過加密後的字符串很難逆向推出原文.

前面那個例子能夠看到, 即便文件被修改了一點點, 也會致使計算後的值發生很大變化.

2.惟一標識

好比說, 如今有十萬個文件, 給你一個文件, 要你在這十萬個文件中查找是否存在. 一個很笨的辦法就是把每一文件都拿出來, 而後按照二進制串一一進行對比. 可是這個操做註定是比較費時的.

能夠用哈希算法對文件進行計算, 而後比較哈希值是否相同. 由於存在哈希衝突的狀況, 你能夠在相同哈希值的文件再進行二進制串比較.

3.哈希表

在哈希表中使用哈希函數已經並不陌生了, 在此再也不贅述。

4.負載均衡

好比說, 如今又多臺服務器, 來了一個請求, 如何肯定這個請求應該路由到哪一個路由器呢?固然, 必須確保相同的請求通過路由到達同一個服務器. 一種辦法就是保存一張路由關係的表, 好比客戶端IP和服務器編號的映射, 可是若是客戶端不少, 勢必查找的時間會很長. 這時, 能夠將客戶端的惟一標識信息(如:IP、username等)進行哈希計算, 而後與服務器個數取模, 獲得的就是服務器的編號.

5.分佈式存儲

當咱們有大量數據時, 通常會選擇將數據存儲到多個服務器, 爲了提升讀取與寫入的速度嘛. 決定將文件存儲到哪臺服務器, 就能夠經過哈希算法取模的操做來獲得。

總結

HASH算法做爲編程應用的基礎知識點,本文主要介紹了HASH算法碰撞,以及經常使用的碰撞解決方案以下:

  • 開放尋址法

  • 再哈希法

  • 鏈地址法

HASH算法經常使用於:

  • 數據校驗

  • 惟一標識

  • 哈希表

  • 負載均衡

  • 分佈式存儲

對於模糊知識點的態度就是反覆研讀推敲,直到能達到理解應用並能給別人講明白的地步,但願對你的工做有所幫助,謝謝!

- END -


做者:架構精進之路,專一軟件架構研究,技術學習與我的成長,關注並私信我回復「01」,送你一份程序員成長進階大禮包。


往期熱文推薦:


「技術架構精進」專一架構研究,技術分享

 

Thanks for reading!

 

本文分享自微信公衆號 - 架構精進之路(jiagou_jingjin)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索