散列(Hash)表

概念

靜態查找表和動態查找樹表的共同特點是記錄在表中的位置和它的關鍵字之間不存在一個確定的關係,查找的過程爲給定值依次和關鍵字集合中各個關鍵字進行比較,查找的效率取決於和給定值進行比較的關鍵字個數。

用這類方法表示的查找表,其平均查找長度都不爲零。不同的表示方法,其差別僅在於:關鍵字和給定值進行比較的順序不同。

對於頻繁使用的查找表,希望ASL=0ASL=0。只有一個辦法:預先知道所查關鍵字在表中的位置,即,要求:記錄在表中位置和其關鍵字之間存在一種確定的關係

因此在一般情況下,需在關鍵字與記錄在表中的存儲位置之間建立一個函數關係,f(key)f(key)作爲關鍵字爲keykey的記錄在表中的位置,通常稱這個函數f(key)f(key)爲散列函數

例如:對於如下 9 個關鍵字{Zhao, Qian, Sun, Li, Wu, Chen, Han, Ye, Dei}設散列函數。

f(key)=(Ord(firstletter)Ord(A)+1)/2f(key) = \lfloor (Ord(first letter) -Ord('A')+1)/2 \rfloor

在這裏插入圖片描述

那麼問題來了,如果現在添加關鍵字Zhou,怎麼辦?
通過函數計算得到的位置已經被佔了。

從這個例子可見:

  1. 散列(Hash)函數是一個映象,即:將關鍵字的集合映射到某個地址集合上,它的設置很靈活,只要這個地址集合的大小不超出允許範圍即可;
  2. 由於散列函數是一個壓縮映象,因此,在一般情況下,很容易產生“衝突”現象,即:key1key2key1 ≠ key2,而 f(key1)=f(key2)f(key1) = f(key2)
  3. 很難找到一個不產生衝突的散列函數。一般情況下,只能選擇恰當的散列函數,使衝突儘可能少地產生。因此,在構造這種特殊的“查找表”時,除了需要選擇一個“好”(儘可能少產生衝突)的散列函數之外;還需要找到一種“處理衝突” 的方法

定義

根據設定的散列函數H(key)H(key)和所選中的處理衝突的方法,將一組關鍵字映象到一個有限的、地址連續的地址集 (區間) 上,並以關鍵字在地址集中的“象”作爲相應記錄在表中的存儲位置,如此構造所得的查找表稱之爲“散列表”。

構造散列函數的方法。

對數字的關鍵字可有下列構造方法:

  1. 直接定址法
  2. 數字分析法
  3. 平方取中法
  4. 摺疊法
  5. 除留餘數法
  6. 隨機數法

若是非數字關鍵字,則需先對其進行數字化處理。

直接定址法

散列函數爲關鍵字的線性函數H(key)=keyH(key) = key或者 H(key)=akey+bH(key) = a * key + b

此法僅適合於:地址集合的大小=關鍵字集合的大小

數字分析法

假設關鍵字集合中的每個關鍵字都是由 s 位數字組成 (u1,u2,...,us)(u1, u2, ..., us),分析關鍵字集中的全體,並從中提取分佈均勻的若干位或它們的組合作爲地址。

此方法僅適合於:能預先估計出全體關鍵字的每一位上各種數字出現的頻度。

平方取中法

以關鍵字的平方值的中間幾位作爲存儲地址。求“關鍵字的平方值” 的目的是“擴大差別”,同時平方值的中間各位又能受到整個關鍵字中各位的影響。

此方法適合於:關鍵字中的每一位都有某些數字重複出現頻度很高的現象。

摺疊法

將關鍵字分割成若干部分,然後取它們的疊加和爲散列地址。有兩種疊加處理的 方法:移位疊加和間界疊加.

此方法適合於: 關鍵字的數字位數特別多。

除留餘數法

設定散列函數爲:H(key)=key MOD pH(key) = key \ MOD \ p 其中,pmp \le m(表長)並且p應爲不大於m的最大素數。


爲什麼要對 p 加限制?(爲什麼非得是素數?)

例如:

給定一組關鍵字爲: 12, 39, 18, 24, 33, 21,若取 p=9p=9, 則他們對應的散列函數值 將爲: 3, 3, 0, 6, 6, 3 可見,若 p 中含質因子 3, 則所有含質因子 3 的關鍵字均映射到“3的倍數”的地址上,從而增加了“衝突”的可能

隨機數法

設定散列函數爲:H(key)=Random(key)H(key) = Random(key)其中,Random爲僞隨機函數。

通常,此方法用於對長度不等的關鍵字構造散列函數。

處理衝突的方法

開放定址法

爲產生衝突的地址H(key)H(key)求得一個地址序列:H0, H1, H2, ..., Hs1sm11≤ s≤m-1

其中:H0=H(key)H0 = H(key)Hi=(H(key)+di) MOD mH_i = ( H(key) + d_i ) \ MOD \ mi=1, 2, ..., s 對增量 did_i 有三種取法:

線性探測再散列

di=c×id_i=c × i 最簡單的情況c=1c=1

實際就是,當發生衝突時,將位置遞增,直到找到第一個爲空的位置爲止。

平方探測再散列

di=12,12,22,22,...,d_i = 1^2, -1^2, 2^2, -2^2, ...,

當發生衝突時,先對當前位置加121^2,如果不爲空,則再加(12)-(1^2),若還不爲空則再加222^2,以此類推,直至找到第一個不爲空的位置爲止。

例子

在這裏插入圖片描述

鏈地址法

將所有散列地址相同的記錄都鏈接在同一鏈表中。

在這裏插入圖片描述

散列表的查找

散列表的查找 查找過程和造表過程一致。假設採用開放定址處理衝突,則查找過程爲:

  • 對於給定值K, 計算散列地址 i=H(K)i = H(K)
  • r[i]=NULLr[i] = NULL 則查找不成功
  • r[i].key=Kr[i].key = K 則查找成功
  • 否則 “求下一地址 HiH_i” ,直至 r[Hi] = NULL (查找不成功)或 r[Hi].key = K (查找成功) 爲止。

散列表的性能

從查找過程得知,散列表查找的平均查找長度實際上並不等於零

決定散列表查找的 ASL 的因素:

  1. 選用的散列函數;
  2. 選用的處理衝突的方法;
  3. 散列表飽和的程度,裝載因子 α=n/mα=n/m 值的大小(n — 記錄數,m — 表的長度)

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章