1. 程式人生 > >理解雜湊表及其查詢

理解雜湊表及其查詢

 以上討論的查詢方法,由於資料元素的儲存位置與關鍵碼之間不存在確定的關係,因此,查詢時,需要進行一系列對關鍵碼的查詢比較,即“查詢演算法”是建立在比較的基礎上的,查詢效率由比較一次縮小的查詢範圍決定。理想的情況是依據關鍵碼直接得到其對應的資料元素位置,即要求關鍵碼與資料元素間存在一一對應關係,通過這個關係,能很快地由關鍵碼得到對應的資料元素位置。

【例7.4】11個元素的關鍵碼分別為 18,27,1,20,22,6,10,13,41,15,25。選取關鍵碼與元素位置間的函式為f(key)=key mod 11
1.通過這個函式對11個元素建立查詢表如下:


雜湊表及其查詢


2.查詢時,對給定值kx依然通過這個函式計算出地址,再將kx與該地址單元中元素的關鍵碼比較,若相等,查詢成功。
雜湊表與雜湊方法:選取某個函式,依該函式按關鍵碼計算元素的儲存位置,並按此存放;查詢時,由同一個函式對給定值kx計算地址,將kx與地址單元中元素關鍵碼進行比,確定查詢是否成功,這就是雜湊方法(雜湊法);雜湊方法中使用的轉換函式稱為雜湊函式(雜湊函式);按這個思想構造的表稱為雜湊表

(雜湊表)。
  對於n個數據元素的集合,總能找到關鍵碼與存放地址一一對應的函式。若最大關鍵為m,可以分配m個數據元素存放單元,選取函式f(key)=key即可,但這樣會造成儲存空間的很大浪費,甚至不可能分配這麼大的儲存空間。通常關鍵碼的集合比雜湊地址集合大得多,因而經過雜湊函式變換後,可能將不同的關鍵碼對映到同一個雜湊地址上,這種現象稱為衝突(Collision),對映到同一雜湊地址上的關鍵碼稱為同義詞。可以說,衝突不可能避免,只能儘可能減少。所以,雜湊方法需要解決以下兩個問題:
1.構造好的雜湊函式
(1)所選函式儘可能簡單,以便提高轉換速度。
(2)所選函式對關鍵碼計算出的地址,應在雜湊地址集中大致均勻分佈,以減少空間
浪費。
2.制定解決衝突的方案。

7.4.2 構造雜湊函式的常用方法

一、直接定址法
Hash(key)=a·key+b  (a、b為常數)
即取關鍵碼的某個線性函式值為雜湊地址,這類函式是一一對應函式,不會產生衝突,但要求地址集合與關鍵碼集合大小相同,因此,對於較大的關鍵碼集合不適用。

【例7.5】關鍵碼集合為{100,300,500,700,800,900},選取雜湊函式為
Hash(key)=key/100,則存放如下:


雜湊表及其查詢


二、除留餘數法
Hash(key)=key mod p  (p是一個整數)
  即取關鍵碼除以p的餘數作為雜湊地址。使用除留餘數法,選取合適的p很重要,若雜湊表表長為m,則要求p≤m,且接近m或等於m。p一般選取質數,也可以是不包含小於20質因子的合數。
三、數字分析法
設關鍵碼集合中,每個關鍵碼均由m位組成,每位上可能有r種不同的符號。
【例7.6】

若關鍵碼是4位十進位制數,則每位上可能有十個不同的數符0~9,所以r=10。

【例7.7】若關鍵碼是僅由英文字母組成的字串,不考慮大小寫,則每位上可能有26種不同的字母,所以r=26。
數字分析法根據r種不同的符號,在各位上的分佈情況,選取某幾位,組合成雜湊地址。所選的位應是各種符號在該位上出現的頻率大致相同。

【例7.8】有一組關鍵碼如下:
3 4 7 0 5 2 4  第1、2位均是“3和4”,第3位也只有
3 4 9 1 4 8 7  “7、8、9”,因此,這幾位不能用,餘
3 4 8 2 6 9 6  下四位分佈較均勻,可作為雜湊地址選用。
3 4 8 5 2 7 0  若雜湊地址是兩位,則可取這四位中的任
3 4 8 6 3 0 5  意兩位組合成雜湊地址,也可以取其中兩
3 4 9 8 0 5 8  位與其它兩位疊加求和後,取低兩位作哈
3 4 7 9 6 7 1  希地址。
3 4 7 3 9  9
─────────────
① ② ③ ④ ⑤ ⑥ ⑦
四、平方取中法
對關鍵碼平方後,按雜湊表大小,取中間的若干位作為雜湊地址。

7.4.3 處理衝突的方法
一、開放定址法
  所謂開放定址法,即是由關鍵碼得到的雜湊地址一旦產生了衝突,也就是說,該地址已經存放了資料元素,就去尋找下一個空的雜湊地址,只要雜湊表足夠大,空的雜湊地址總能找到,並將資料元素存入。
找空雜湊地址方法很多,下面介紹三種:
1.線性探測法
Hi=(Hash(key)+di) mod m  ( 1≤i < m )
其中:
Hash(key)為雜湊函式
m為雜湊表長度
di 為增量序列1,2,……,m-1,且di=i

【例7.9】關鍵碼集為 {47,7,29,11,16,92,22,8,3},雜湊表表長為11,
Hash(key)=key mod 11,用線性探測法處理衝突,建表如下:


雜湊表及其查詢


47、7、11、16、92均是由雜湊函式得到的沒有衝突的雜湊地址而直接存入的;
Hash(29)=7,雜湊地址上衝突,需尋找下一個空的雜湊地址:
由H1=(Hash(29)+1) mod 11=8,雜湊地址8為空,將29存入。另外,22、8同樣在雜湊地址上有衝突,也是由H1找到空的雜湊地址的;
而Hash(3)=3,雜湊地址上衝突,由
H1=(Hash(3)+1) mod 11=4  仍然衝突;
H2=(Hash(3)+2) mod 11=5  仍然衝突;
H3=(Hash(3)+3) mod 11=6  找到空的雜湊地址,存入。
  線性探測法可能使第i個雜湊地址的同義詞存入第i+1個雜湊地址,這樣本應存入第i+1個雜湊地址的元素變成了第i+2個雜湊地址的同義詞,……,因此,可能出現很多元素在相鄰的雜湊地址上“堆積”起來,大大降低了查詢效率。為此,可採用二次探測法,或雙雜湊函式探測法,以改善“堆積”問題。
2.二次探測法
Hi=(Hash(key)±di) mod m
其中:
Hash(key)為雜湊函式
m為雜湊表長度,m要求是某個4k+3的質數(k是整數)


雜湊表及其查詢


仍以上例用二次探測法處理衝突,建表如下:


雜湊表及其查詢


對關鍵碼尋找空的雜湊地址只有3這個關鍵碼與上例不同,
Hash(3)=3,雜湊地址上衝突,由
H1=(Hash(3)+12) mod 11=4  仍然衝突;
H2=(Hash(3)-12) mod 11=2  找到空的雜湊地址,存入。
3.雙雜湊函式探測法
Hi=(Hash(key)+i*ReHash(key)) mod m  (i=1,2,……,m-1)
其中:
Hash(key),ReHash(key)是兩個雜湊函式,
m為雜湊表長度
雙雜湊函式探測法,先用第一個函式Hash(key)對關鍵碼計算雜湊地址,一旦產生地址衝突,再用第二個函式ReHash(key)確定移動的步長因子,最後,通過步長因子序列由探測函式尋找空的雜湊地址。
比如,Hash(key)=a時產生地址衝突,就計算ReHash(key)=b,則探測的地址序列為
H1=(a+b) mod m,H2=(a+2b) mod m,……,Hm-1=(a+(m-1)b) mod m


雜湊表及其查詢


二、鏈地址法
  設雜湊函式得到的雜湊地址域在區間[0,m-1]上,以每個雜湊地址作為一個指標,指向一個鏈,即分配指標陣列ElemType *eptr[m];建立m個空連結串列,由雜湊函式對關鍵碼轉
換後,對映到同一雜湊地址i的同義詞均加入到*eptr[i]指向的連結串列中。

【例9.l3】關鍵碼序列為47,7,29,11,16,92,22,8,3,50,37,89,94,21,雜湊函式為
Hash(key)=key mod 11
用拉鍊法處理衝突,建表如圖9.21。圖9.21拉鍊法處理衝突時的雜湊表(向連結串列中插入元素均在表頭進行)
三.建立一個公共溢位區
設雜湊函式產生的雜湊地址集為[0,m-1],則分配兩個表:
一個基本表ElemType base_tbl[m];每個單元只能存放一個元素;
一個溢位表ElemType over_tbl[k];只要關鍵碼對應的雜湊地址在基本表上產生衝突,則所有這樣的元素一律存入該表中。查詢時,對給定值kx通過雜湊函式計算出雜湊地址i,先與基本表的base_tbl[i]單元比較,若相等,查詢成功;否則,再到溢位表中進行查詢。

7.4.4 雜湊表的查詢分析
  雜湊表的查詢過程基本上和造表過程相同。一些關鍵碼可通過雜湊函式轉換的地址直接找到,另一些關鍵碼在雜湊函式得到的地址上產生了衝突,需要按處理衝突的方法進行查詢。在介紹的三種處理衝突的方法中,產生衝突後的查詢仍然是給定值與關鍵碼進行比較的過程。所以,對雜湊表查詢效率的量度,依然用平均查詢長度來衡量。
  查詢過程中,關鍵碼的比較次數,取決於產生衝突的多少,產生的衝突少,查詢效率就高,產生的衝突多,查詢效率就低。因此,影響產生衝突多少的因素,也就是影響查詢效率的因素。影響產生衝突多少有以下三個因素:
1.雜湊函式是否均勻; 
2.處理衝突的方法; 
3.雜湊表的裝填因子。
  分析這三個因素,儘管雜湊函式的“好壞”直接影響衝突產生的頻度,但一般情況下,我們總認為所選的雜湊函式是“均勻的”,因此,可不考慮雜湊函式對平均查詢長度的影響。就線性探測法和二次探測法處理衝突的例子看,相同的關鍵碼集合、同樣的雜湊函式,但在資料元素查詢等概率情況下,它們的平均查詢長度卻不同:
線性探測法的平均查詢長度ASL=(5×1+3×2+1×4)/9=5/3
二次探測法的平均查詢長度ASL=(5×1+3×2+1×2)/9=13/9
填入表中的元素個數
雜湊表的裝填因子定義為:α=────────────
雜湊表的長度
  α是雜湊表裝滿程度的標誌因子。由於表長是定值,α與“填入表中的元素個數”成正比,所以,α越大,填入表中的元素較多,產生衝突的可能性就越大;α越小,填入表中的元素較少,產生衝突的可能性就越小。
  實際上,雜湊表的平均查詢長度是裝填因子α的函式,只是不同處理衝突的方法有不同的函式。以下給出幾種不同處理衝突方法的平均查詢長度:


雜湊表及其查詢


雜湊方法存取速度快,也較節省空間,靜態查詢、動態查詢均適用,但由於存取是隨機的,因此,不便於順序查詢。