哈希表、哈希算法、一致性哈希表

哈希表定義

????散列表(Hash table,也叫哈希表),是根據(jù)關鍵碼值(Key value)而直接進行訪問的數(shù)據(jù)結構。它通過把關鍵碼映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數(shù)叫做散列函數(shù)(哈希函數(shù)),存放記錄的數(shù)組叫做散列表。

哈希表優(yōu)缺點

? 優(yōu)點:

??????哈希表可以提供快速的操作。

缺點:

? ????? 哈希表通常是基于數(shù)組的,數(shù)組創(chuàng)建后難于擴展。

????????也沒有一種簡便的方法可以以任何一種順序〔例如從小到大)遍歷表中的數(shù)據(jù)項。

????綜上,如果不需要有序遍歷數(shù)據(jù),井且可以提前預測數(shù)據(jù)量的大小。那么哈希表在速度和易用性方面是無與倫比的。


哈希查找

????????1.?使用哈希函數(shù)將被查找的鍵轉(zhuǎn)換為數(shù)組的索引。

????????2.?處理哈希碰撞沖突。


散列函數(shù)

????若關鍵字為k,則其值存放在f(k)的存儲位置上。由此,不需比較便可直接取得所查記錄。稱這個對應關系f為散列函數(shù),按這個思想建立的表為散列表。

????若對于關鍵字集合中的任一個關鍵字,經(jīng)散列函數(shù)映象到地址集合中任何一個地址的概率是相等的,則稱此類散列函數(shù)為均勻散列函數(shù)(Uniform Hash function),這就是使關鍵字經(jīng)過散列函數(shù)得到一個"隨機的地址",從而減少碰撞。

散列函數(shù)能使對一個數(shù)據(jù)序列的訪問過程更加迅速有效,通過散列函數(shù),數(shù)據(jù)元素將被更快地定位。

一個好的散列函數(shù)一般應該考慮下列因素

????1.計算簡單,以便提高轉(zhuǎn)換速度。

????2.關鍵詞對應的地址空間分布均勻,以盡量減少沖突。


常見的 散列函數(shù) :

1.?? 直接尋址法

????取關鍵字或者關鍵字的某個線性函數(shù)值作為哈希地址,即H(Key)=Key或者H(Key)=a*Key+b(a,b為整數(shù)),這種散列函數(shù)也叫做自身函數(shù).如果H(Key)的哈希地址上已經(jīng)有值了,那么就往下一個位置找,直到找到H(Key)的位置沒有值了就把元素放進去。

2.?? 數(shù)字分析法

????數(shù)字分析法就是找出數(shù)字的規(guī)律,盡可能利用這些數(shù)據(jù)來構造沖突幾率較低的散列地址。

3.?? 平方取中法

????取關鍵字平方后的中間幾位作為散列地址。這種方法的原理是通過取平方擴大差別,平方值的中間幾位和這個數(shù)的每一位都相關,則對不同的關鍵字得到的哈希函數(shù)值不易產(chǎn)生沖突,由此產(chǎn)生的哈希地址也較為均勻。該方法適用于關鍵字中的每一位都有某些數(shù)字重復出現(xiàn)頻度很高的現(xiàn)象。

4.?? 折疊法

????折疊法是將關鍵字分割成位數(shù)相同的幾部分,最后一部分位數(shù)可以不同,然后取這幾部分的疊加和(注意:疊加和時去除進位)作為散列地址。

????數(shù)位疊加可以有移位疊加和間界疊加兩種方法。移位疊加是將分割后的每一部分的最低位對齊,然后相加;間界疊加是從一端向另一端沿分割界來回折疊,然后對齊相加。

????該方法適用于關鍵字特別多的情況。

5.?? 隨機數(shù)法

????選擇一個隨機數(shù),作為散列地址,通常用于關鍵字長度不同的場合。

6.?? 除留余數(shù)法

????取關鍵字被某個不大于散列表表長m的數(shù)p除后所得的余數(shù)為散列地址.即H(Key)=Key MOD p,p<=m.不僅可以對關鍵字直接取模,也可在折疊、平方取中等運算之后取模。對p的選擇很重要,一般取素數(shù)或m,若p選得不好,則很容易產(chǎn)生沖突。

處理沖突

????對不同的關鍵字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),這種現(xiàn)象稱為碰撞(英語:Collision)。具有相同函數(shù)值的關鍵字對該散列函數(shù)來說稱做同義詞。

????通過構造性能良好的散列函數(shù),可以減少沖突,但一般不可能完全避免沖突,因此解決沖突是哈希法的另一個關鍵問題。創(chuàng)建哈希表和查找哈希表都會遇到?jīng)_突,兩種情況下解決沖突的方法應該一致。

下面以創(chuàng)建哈希表為例,說明解決沖突的方法。

1.開放定址法

????這種方法也稱再散列法,其基本思想是:當關鍵字key的哈希地址p=H(key)出現(xiàn)沖突時,以p為基礎,產(chǎn)生另一個哈希地址p1,如果p1仍然沖突,再以p為基礎,產(chǎn)生另一個哈希地址p2,…,直到找出一個不沖突的哈希地址pi ,將相應元素存入其中。這種方法有一個通用的再散列函數(shù)形式:Hi=(H(key)+di)%m?? i=1,2,…,m-1,其中H(key)為哈希函數(shù),m 為表長,di稱為增量序列,i為碰撞次數(shù)。增量序列的取值方式不同,相應的再散列方式也不同。增量序列主要有以下幾種:

????(1)?線性探測再散列

????????di=1,2,3,…,m-1

????????這種方法的特點是:沖突發(fā)生時,順序查看表中下一單元,直到找出一個空單元或查遍全表。

????(2)二次探測再散列

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

????????這種方法的特點是:沖突發(fā)生時,在表的左右進行跳躍式探測,比較靈活。

????(3)偽隨機探測再散列

????????di=偽隨機數(shù)序列。

????線性探測再散列的優(yōu)點是:只要哈希表不滿,就一定能找到一個不沖突的哈希地址,而二次探測再散列和偽隨機探測再散列則不一定。線性探測再散列容易產(chǎn)生“二次聚集”,即在處理同義詞的沖突時又導致非同義詞的沖突。

????其實除了上面的幾種方法,開放定址法還有很多變種,不過都是對di有不同的表示方法。(如雙散列探測法:di=i*h2(k))

2.再哈希法

????這種方法是同時構造多個不同的哈希函數(shù):Hi=RHi(key),i=1,2,3,…,n。

????當哈希地址H1=RH1(key)發(fā)生沖突時,再計算H2=RH2(key)……,直到?jīng)_突不再產(chǎn)生。這種方法不易產(chǎn)生聚集,但增加了計算時間。

?3.鏈地址法(拉鏈法)

????這種方法的基本思想是將所有哈希地址相同的元素構成一個稱為同義詞鏈的單鏈表,并將單鏈表的頭指針存在哈希表(數(shù)組)中,因而查找、插入和刪除主要在同義詞鏈中進行。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指針組成的指針數(shù)組T[0..m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應為空指針。鏈地址法適用于經(jīng)常進行插入和刪除的情況。


拉鏈法

? ??拉鏈法的優(yōu)點

????????與開放定址法相比,拉鏈法有如下幾個優(yōu)點:

????????????(1)拉鏈法處理沖突簡單,且無堆積現(xiàn)象,即非同義詞決不會發(fā)生沖突,因此平均查找長度較短;

????????????(2)由于拉鏈法中各鏈表上的結點空間是動態(tài)申請的,故它更適合于造表前無法確定表長的情況;

????????????(3)開放定址法為減少沖突,要求裝填因子α較小,故當結點規(guī)模較大時會浪費很多空間。而拉鏈法中理論上可取α≥1,且結點較大時,拉鏈法中增加的指針域可忽略不計,因此節(jié)省空間;(散列表的裝填因子定義為:α= 填入表中的元素個數(shù) / 散列表的長度)

注:HashMap默認裝填因子是0.75。

????????????(4)在用拉鏈法構造的散列表中,刪除結點的操作易于實現(xiàn)。只要簡單地刪去鏈表上相應的結點即可。而對開放定址法構造的散列表,刪除結點不能簡單地將被刪結點的空間置為空,否則將截斷在它之后填入散列表的同義詞結點的查找路徑。這是因為各種開放定址法中,空地址單元都被理解沒有查找到元素。 因此在用開放定址法處理沖突的散列表上執(zhí)行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

? ??拉鏈法的缺點

????????拉鏈法的缺點是:指針需要額外的空間,故當結點規(guī)模較小時,開放定址法較為節(jié)省空間,此時將節(jié)省的指針空間用來擴大散列表的規(guī)模,可使裝填因子變小,這又減少了開放定址法中的沖突,從而提高平均查找速度。

4、建立公共溢出區(qū)

????這種方法的基本思想是:將哈希表分為基本表和溢出表兩部分,凡是和基本表發(fā)生沖突的元素,一律填入溢出表(在這個方法里面是把元素分開兩個表來存儲)。

查找性能

????散列表的查找過程基本上和造表過程相同。一些關鍵碼可通過散列函數(shù)轉(zhuǎn)換的地址直接找到,另一些關鍵碼在散列函數(shù)得到的地址上產(chǎn)生了沖突,需要按處理沖突的方法進行查找。在介紹的三種處理沖突的方法中,產(chǎn)生沖突后的查找仍然是給定值與關鍵碼進行比較的過程。所以,對散列表查找效率的量度,依然用平均查找長度來衡量。

????查找過程中,關鍵碼的比較次數(shù),取決于產(chǎn)生沖突的多少,產(chǎn)生的沖突少,查找效率就高,產(chǎn)生的沖突多,查找效率就低。因此,影響產(chǎn)生沖突多少的因素,也就是影響查找效率的因素。

影響產(chǎn)生沖突多少有以下三個因素:

????1. 散列函數(shù)是否均勻;

????2. 處理沖突的方法;

????3. 散列表的裝填因子。

????散列表的裝填因子

????????定義為:α= 填入表中的元素個數(shù) / 散列表的長度

????????α是散列表裝滿程度的標志因子。由于表長是定值,α與"填入表中的元素個數(shù)"成正比,所以,α越大,填入表中的元素較多,產(chǎn)生沖突的可能性就越大;α越小,填入表中的元素較少,產(chǎn)生沖突的可能性就越小。

????????實際上,散列表的平均查找長度是裝填因子α的函數(shù),只是不同處理沖突的方法有不同的函數(shù)。


哈希算法

????這個HASH算法不是大學里數(shù)據(jù)結構課里那個HASH表的算法。這里的HASH算法是密碼學的基礎,了解了hash基本定義,就不能不提到一些著名的hash算法,MD5 和 SHA-1 可以說是目前應用最廣泛的Hash算法,而它們都是以 MD4 為基礎設計的。

Hash算法在信息安全方面的應用主要體現(xiàn)在以下的3個方面:

? ??⑴?文件校驗

????????我們比較熟悉的校驗算法有奇偶校驗和CRC校驗,這2種校驗并沒有抗數(shù)據(jù)篡改的能力,它們一定程度上能檢測出數(shù)據(jù)傳輸中的信道誤碼,但卻不能防止對數(shù)據(jù)的惡意破壞。

????????MD5 Hash算法的"數(shù)字指紋"特性,使它成為目前應用最廣泛的一種文件完整性校驗和(Checksum)算法,不少Unix系統(tǒng)有提供計算md5 checksum的命令。

? ??⑵?數(shù)字簽名

????????Hash 算法也是現(xiàn)代密碼體系中的一個重要組成部分。由于非對稱算法的運算速度較慢,所以在數(shù)字簽名協(xié)議中,單向散列函數(shù)扮演了一個重要的角色。對 Hash 值,又稱"數(shù)字摘要"進行數(shù)字簽名,在統(tǒng)計上可以認為與對文件本身進行數(shù)字簽名是等效的。而且這樣的協(xié)議還有其他的優(yōu)點。

? ??⑶ 鑒權協(xié)議

????????如下的鑒權協(xié)議又被稱作挑戰(zhàn)--認證模式:在傳輸信道是可被偵聽,但不可被篡改的情況下,這是一種簡單而安全的方法。



一致性哈希表

????一致性哈希表簡稱DHT,主要應用于分布式緩存中,可以用來解決分布式存儲結構下動態(tài)增加和刪除節(jié)點所帶來的問題。比如,一個分布式的存儲系統(tǒng),要將數(shù)據(jù)存儲到具體的節(jié)點上,如果采用普通的hash方法,將數(shù)據(jù)映射到具體的節(jié)點上,如key%N(key是數(shù)據(jù)的key,N是機器節(jié)點數(shù)),如果有一個機器加入或退出這個集群,則所有的數(shù)據(jù)映射都無效了,如果是持久化存儲則要做數(shù)據(jù)遷移,如果是分布式緩存,則其他緩存就失效了。

判定哈希算法好壞的四個定義

????1、平衡性(Balance):平衡性是指哈希的結果能夠盡可能分布到所有的緩沖中去,這樣可以使得所有的緩沖空間都得到利用。

????2、單調(diào)性(Monotonicity):單調(diào)性是指如果已經(jīng)有一些內(nèi)容通過哈希分派到了相應的緩沖中,又有新的緩沖加入到系統(tǒng)中。哈希的結果應能夠保證原有已分配的內(nèi)容可以被映射到原有的或者新的緩沖中去,而不會被映射到舊的緩沖集合中的其他緩沖區(qū)。

????3、分散性(Spread):在分布式環(huán)境中,終端有可能看不到所有的緩沖,而是只能看到其中的一部分。當終端希望通過哈希過程將內(nèi)容映射到緩沖上時,由于不同終端所見的緩沖范圍有可能不同,從而導致哈希的結果不一致,最終的結果是相同的內(nèi)容被不同的終端映射到不同的緩沖區(qū)中。這種情況顯然是應該避免的,因為它導致相同內(nèi)容被存儲到不同緩沖中去,降低了系統(tǒng)存儲的效率。分散性的定義就是上述情況發(fā)生的嚴重程度。好的哈希算法應能夠盡量避免不一致的情況發(fā)生,也就是盡量降低分散性。

????4、負載(Load):負載問題實際上是從另一個角度看待分散性問題。既然不同的終端可能將相同的內(nèi)容映射到不同的緩沖區(qū)中,那么對于一個特定的緩沖區(qū)而言,也可能被不同的用戶映射為不同的內(nèi)容。與分散性一樣,這種情況也是應當避免的,因此好的哈希算法應能夠盡量降低緩沖的負荷。

????在分布式集群中,對機器的添加刪除,或者機器故障后自動脫離集群這些操作是分布式集群管理最基本的功能。如果采用常用的hash取模算法,那么在有機器添加或者刪除后,很多原有的數(shù)據(jù)就無法找到了,這樣嚴重的違反了單調(diào)性原則。接下來主要說明一下一致性哈希算法是如何設計的。

以SpyMemcached的ketama算法來說,思路是這樣的:

把數(shù)據(jù)用hash函數(shù),映射到一個很大的空間里,如圖所示。數(shù)據(jù)的存儲時,先得到一個hash值,對應到這個環(huán)中的每個位置,如k1對應到了圖中所示的位置,然后沿順時針找到一個機器節(jié)點B,將k1存儲到B這個節(jié)點中。

如果B節(jié)點宕機了,則B上的數(shù)據(jù)就會落到C節(jié)點上,如下圖所示:

這樣,只會影響C節(jié)點,對其他的節(jié)點A,D的數(shù)據(jù)不會造成影響。然而,這又會造成一個“雪崩”的情況,即C節(jié)點由于承擔了B節(jié)點的數(shù)據(jù),所以C節(jié)點的負載會變高,C節(jié)點很容易也宕機,這樣依次下去,這樣造成整個集群都掛了。

為此,引入了“虛擬節(jié)點”的概念:即把想象在這個環(huán)上有很多“虛擬節(jié)點”,數(shù)據(jù)的存儲是沿著環(huán)的順時針方向找一個虛擬節(jié)點,每個虛擬節(jié)點都會關聯(lián)到一個真實節(jié)點,如下圖所使用:

圖中的A1、A2、B1、B2、C1、C2、D1、D2都是虛擬節(jié)點,機器A負載存儲A1、A2的數(shù)據(jù),機器B負載存儲B1、B2的數(shù)據(jù),機器C負載存儲C1、C2的數(shù)據(jù)。由于這些虛擬節(jié)點數(shù)量很多,均勻分布,因此不會造成“雪崩”現(xiàn)象。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 哈希表:即散列存儲結構。散列法存儲的基本思想:建立記錄關鍵碼字與其存儲位置的對應關系,或者說,由關鍵碼的值決定數(shù)據(jù)...
    linbj閱讀 6,654評論 1 5
  • 散列表,它是基于快速存取的角度設計的,也是一種典型的“空間換時間”的做法。顧名思義,該數(shù)據(jù)結構可以理解為一個線性表...
    yeying12321閱讀 3,779評論 0 6
  • 什么是哈希表? 哈希表(Hash table,也叫散列表),是根據(jù)關鍵碼值(Key value)而直接進行訪問的數(shù)...
    郝程序猿閱讀 2,285評論 1 7
  • 今日不靜心 明日亦不能靜心 即刻不靜心 下刻亦不能靜心
    云_41b5閱讀 251評論 0 0
  • 六天 還有六天就2016了 這時間說快不快說慢不慢 一眨眼 又一年 以前 初中的時候 無憂無慮的 我也不是...
    喲喲嘻嘻閱讀 502評論 0 0

友情鏈接更多精彩內(nèi)容