哈希表詳解

哈希表:即散列存儲結構。
散列法存儲的基本思想:建立記錄關鍵碼字與其存儲位置的對應關系,或者說,由關鍵碼的值決定數據的存儲地址。
這樣,不經過比較,一次存取就能得到所查元素的查找方法
優點:查找速度極快(O(1)),查找效率與元素個數n無關!

哈希方法(雜湊法)
選取某個函數,依該函數按關鍵字計算元素的存儲位置并按此存放;查找時也由同一個函數對給定值k計算地址,將k與地址中內容進行比較,確定查找是否成功。

哈希函數(雜湊函數)
哈希方法中使用的轉換函數稱為哈希函數(雜湊函數).在記錄的關鍵碼與記錄的存儲地址之間建立的一種對應關系

例:

有數據元素序列(14,23,39,9,25,11),若規定每個元素k的存儲地址H(k)=k , H(k)稱為散列函數,畫出存儲結構圖。


image.png

根據散列函數H(k)=k ,可知元素14應當存入地址為14的單元,元素23應當存入地址為23的單元,……,

如何進行散列查找?

根據存儲時用到的散列函數H(k)表達式,迅即可查到結果!
例如,查找key=9,則訪問H(9)=9號地址,若內容為9則成功;
若查不到,應當設法返回一個特殊值,例如空指針或空記錄。
很顯然這種搜索方式空間效率過低。

哈希函數可寫成:addr(ai)=H(ki)

選取某個函數,依該函數按關鍵字計算元素的存儲位置并按此存放;查找時也由同一個函數對給定值k計算地址,將k與地址中內容進行比較,確定查找是否成功。哈希方法中使用的轉換函數稱為哈希函數(雜湊函數).在記錄的關鍵碼與記錄的存儲地址之間建立的一種對應關系。

可能導致的沖突

通常關鍵碼的集合比哈希地址集合大得多,因而經過哈希函數變換后,可能將不同的關鍵碼映射到同一個哈希地址上,這種現象稱為沖突。

例.

有6個元素的關鍵碼分別為:(14,23,39,9,25,11)。
選取關鍵碼與元素位置間的函數為H(k)=k mod 7

image.png

根據哈希函數算出來發現同一個地址放了多個關鍵碼,也就是沖突了。
在哈希查找方法中,沖突是不可能避免的,只能盡可能減少。
所以,哈希方法必須解決以下兩個問題:

1)構造好的哈希函數
(a)所選函數盡可能簡單,以便提高轉換速度;
(b)所選函數對關鍵碼計算出的地址,應在哈希地址內集中并大致均勻分布,以減少空間浪費。

2)制定一個好的解決沖突的方案
查找時,如果從哈希函數計算出的地址中查不到關鍵碼,則應當依據解決沖突的規則,有規律地查詢其它相關單元。

從上面兩個例子可以得出如下結論:
哈希函數只是一種映象,所以哈希函數的設定很靈活,只要使任何關鍵碼的哈希函數值都落在表長允許的范圍之內即可
沖突:key1≠key2,但H(key1)=H(key2)
同義詞:具有相同函數值的兩個關鍵碼
哈希函數沖突不可避免,只能盡量減少。所以,哈希方法解決兩個問題:
構造好的哈希函數;

制定解決沖突基本要求:
要求一:n個數據原僅占用n個地址,雖然散列查找是以空間換時間,但仍希望散列的地址空間盡量小。
要求二:無論用什么方法存儲,目的都是盡量均勻地存放元素,以避免沖突。

常用的哈希函數構造方法有:

  • 直接定址法
  • 除留余數法
  • 乘余取整法
  • 數字分析法
  • 平方取中法
  • 折疊法
  • 隨機數法

1、直接定址法

Hash(key) = a·key + b (a、b為常數)
優點:以關鍵碼key的某個線性函數值為哈希地址,不會產生沖突.
缺點:要占用連續地址空間,空間效率低。

例.關鍵碼集合為{100,300,500,700,800,900},
選取哈希函數為Hash(key)=key/100,
則存儲結構(哈希表)如下:


image.png

2、除留余數法

Hash(key)=key mod p (p是一個整數)
特點:以關鍵碼除以p的余數作為哈希地址。
關鍵:如何選取合適的p?p選的不好,容易產生同義詞
技巧:若設計的哈希表長為m,則一般取p≤m且為質數
(也可以是合數,但不能包含小于20的質因子)。

3、乘余取整法

Hash(key)= ? B( Akey mod 1 ) ?
(A、B均為常數,且0<A<1,B為整數)
特點:以關鍵碼key乘以A,取其小數部分,然后再放大B倍并取整,作為哈希地址。
例:欲以學號最后兩位作為地址,則哈希函數應為:
H(k)=100(0.01k % 1 )
其實也可以用法2實現: H(k)=k % 100

4、數字分析法

特點:選用關鍵字的某幾位組合成哈希地址。選用原則應當是:各種符號在該位上出現的頻率大致相同。
例:有一組(例如80個)關鍵碼,其樣式如下:


image.png

討論:
① 第1、2位均是“3和4”,第3位也只有“ 7、8、9”,因此,這幾位不能用,余下四位分布較均勻,可作為哈希地址選用。

② 若哈希地址取兩位(因元素僅80個),則可取這四位中的任意兩位組合成哈希地址,也可以取其中兩位與其它兩位疊加求和后,取低兩位作哈希地址。

5、平方取中法

特點:對關鍵碼平方后,按哈希表大小,取中間的若干位作為哈希地址。(適于不知道全部關鍵碼情況)
理由:因為中間幾位與數據的每一位都相關。
例:2589的平方值為6702921,可以取中間的029為地址。

6、折疊法

特點:將關鍵碼自左到右分成位數相等的幾部分(最后一部分位數可以短些),然后將這幾部分疊加求和,并按哈希表表長,取后幾位作為哈希地址。
適用于:關鍵碼位數很多,且每一位上各符號出現概率大致相同的情況。
法1:移位法 ── 將各部分的最后一位對齊相加。
法2:間界疊加法──從一端向另一端沿分割界來回折疊后,最后一位對齊相加。
例:元素42751896,
用法1: 427+518+96=1041
用法2: 427 518 96—> 724+518+69 =1311

7、隨機數法
Hash(key) = random ( key ) (random為偽隨機函數)
適用于:關鍵字長度不等的情況。造表和查找都很方便。

小結:構造哈希函數的原則:
① 執行速度(即計算哈希函數所需時間);
② 關鍵字的長度;
③ 哈希表的大??;
④ 關鍵字的分布情況;
⑤ 查找頻率。

三、沖突處理方法

  • 開放定址法(開地址法)
  • 鏈地址法(拉鏈法)
  • 再哈希法(雙哈希函數法)
  • 建立一個公共溢出區

1、開放定址法(開地址法)

設計思路:有沖突時就去尋找下一個空的哈希地址,只要哈希表足夠大,空的哈希地址總能找到,并將數據元素存入。
1)線性探測法
Hi=(Hash(key)+di) mod m ( 1≤i < m )
其中:
Hash(key)為哈希函數
m為哈希表長度
di 為增量序列 1,2,…m-1,且di=i

關鍵碼集為 {47,7,29,11,16,92,22,8,3},
設:哈希表表長為m=11;
哈希函數為Hash(key)=key mod 11;
擬用線性探測法處理沖突。建哈希表如下:

image.png

解釋:
① 47、7是由哈希函數得到的沒有沖突的哈希地址;
② Hash(29)=7,哈希地址有沖突,需尋找下一個空的哈希地址:由H1=(Hash(29)+1) mod 11=8,哈希地址8為空,因此將29存入。
③ 另外,22、8、3同樣在哈希地址上有沖突,也是由H1找到空的哈希地址的。
其中3 還連續移動了(二次聚集)

線性探測法的優點:只要哈希表未被填滿,保證能找到一個空地址單元存放有沖突的元素;
線性探測法的缺點:可能使第i個哈希地址的同義詞存入第i+1個哈希地址,這樣本應存入第i+1個哈希地址的元素變成了第i+2個哈希地址的同義詞,……,
因此,可能出現很多元素在相鄰的哈希地址上“堆積”起來,大大降低了查找效率。
解決方案:可采用二次探測法或偽隨機探測法,以改善“堆積”問題。

2) 二次探測法
仍舉上例,改用二次探測法處理沖突,建表如下:
Hi=(Hash(key)±di) mod m
其中:Hash(key)為哈希函數
m為哈希表長度,m要求是某個4k+3的質數;
di為增量序列 1^2,-1 ^2,2 ^2,-2 ^2,…,q ^2


image.png

注:只有3這個關鍵碼的沖突處理與上例不同,
Hash(3)=3,哈希地址上沖突,由
H1=(Hash(3)+1 ^2) mod 11=4,仍然沖突;
H2=(Hash(3)-1 ^2) mod 11=2,找到空的哈希地址,存入。

3) 若di=偽隨機序列,就稱為偽隨機探測法

2、鏈地址法(拉鏈法)

基本思想:將具有相同哈希地址的記錄(所有關鍵碼為同義詞)鏈成一個單鏈表,m個哈希地址就設m個單鏈表,然后用一個數組將m個單鏈表的表頭指針存儲起來,形成一個動態的結構。

設{ 47, 7, 29, 11, 16, 92, 22, 8, 3, 50, 37, 89 }的哈希函數為:
Hash(key)=key mod 11,
用拉鏈法處理沖突,則建表如圖所示。


image.png

3、再哈希法(雙哈希函數法)

Hi=RHi(key) i=1, 2, …,k
RHi均是不同的哈希函數,當產生沖突時就計算另一個哈希函數,直到沖突不再發生。
優點:不易產生聚集;
缺點:增加了計算時間。

4. 建立一個公共溢出區

思路:除設立哈?;颈硗?,另設立一個溢出向量表。
所有關鍵字和基本表中關鍵字為同義詞的記錄,不管它們由哈希函數得到的地址是什么,一旦發生沖突,都填入溢出表。

哈希表的查找及分析

明確:散列函數沒有“萬能”通式(雜湊法),要根據元素集合的特性而分別構造。
討論:哈希查找的速度是否為真正的O(1)?
不是。由于沖突的產生,使得哈希表的查找過程仍然要進行比較,仍然要以平均查找長度ASL來衡量。
一般地,ASL依賴于哈希表的裝填因子α,它標志著哈希表的裝滿程度。


image.png

0≤α≤1
α 越大,表中記錄數越多,說明表裝得越滿,發生沖突的可能性就越大,查找時比較次數就越多。

例 已知一組關鍵字(19,14,23,1,68,20,84,27,55,11,10,79)
哈希函數為:H(key)=key MOD 13, 哈希表長為m=16,
設每個記錄的查找概率相等
(1) 用線性探測再散列處理沖突,即Hi=(H(key)+di) MOD m


image.png
H(19)=6
H(14)=1
H(23)=10
H(1)=1     沖突,H1=(1+1) MOD16=2
H(68)=3
H(20)=7
H(84)=6   沖突,H1=(6+1)MOD16=7
                 沖突,H2=(6+2)MOD16=8
H(27)=1   沖突,H1=(1+1)MOD16=2
                 沖突,H2=(1+2)MOD16=3
                 沖突,H3=(1+3)MOD16=4
H(55)=3   沖突,H1=(3+1)MOD16=4
                 沖突,H2=(3+2)MOD16=5
H(11)=11
H(10)=10  沖突,H1=(10+1)MOD16=11
                  沖突,H2=(10+2)MOD16=12
H(79)=1    沖突,H1=(1+1)MOD16=2
                  沖突,H2=(1+2)MOD16=3
                  沖突,H3=(1+3)MOD16=4
                  沖突,H4=(1+4)MOD16=5
                  沖突,H5=(1+5)MOD16=6
                  沖突,H6=(1+6)MOD16=7
                  沖突,H7=(1+7)MOD16=8
                  沖突,H8=(1+8)MOD16=9
ASL=(1*6+2+3*3+4*1+9*1)/12=2.5

(2) 用二次探測再散列處理沖突,即Hi=(H(key)+di) MOD m


image.png
H(19)=6
H(14)=1
H(23)=10
H(1)=1沖突, H1=(1+12) MOD16=2
H(68)=3
H(20)=7
H(84)=6   沖突,H1=(6+12)MOD16=7
                 沖突,H2=(6﹣12)MOD16=5
H(27)=1   沖突,H1=(1+12 )MOD16=2
                 沖突,H2=(1 -12 )MOD16=0
H(55)=3   沖突,H1=(3+12)MOD16=4
H(11)=11
H(10)=10  沖突,H1=(10+12)MOD16=11
                  沖突,H2=(10 ﹣12 )MOD16=9
H(79)=1    沖突,H1=(1 +12 )MOD16=2
                  沖突,H2=(1﹣12)MOD16=0
                  沖突,H3=(1+ 22)MOD16=5
                  沖突,H4=(1﹣22)MOD16=13

ASL=(1*6+2*2+3*3+5*1)/12=2

(3) 用鏈地址法處理沖突

image.png

ASL=(16+24+31+41)/12=1.75

討論:

1) 散列存儲的查找效率到底是多少?
答:ASL與裝填因子α有關!既不是嚴格的O(1),也不是O(n)
2)“沖突”是不是特別討厭?
答:不一定!正因為有沖突,使得文件加密后無法破譯?。▎蜗蛏⒘泻瘮挡豢赡?,常用于數字簽名和間接加密)。
利用了哈希表性質:源文件稍稍改動,會導致哈希表變動很大。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容