雜湊函式的構造方法以及衝突解決辦法

2021-06-07 07:07:49 字數 4218 閱讀 2822

常用的構造雜湊函式的方法有:

h(key)=key 或 h(key)=a·key+b

其中a和b為常數(這種雜湊函式叫做自身函式)。

[例如]:有乙個從1歲到100歲的人口數字統計表,其中,年齡作為關鍵字,雜湊函式取關鍵字自身。這樣,若要詢問25歲的人有多少,則只要查表的第25項即可。

[又如]:有乙個解放後出生的人口調查表,關鍵字是年份,雜湊函式取關鍵字加一常數 h(key)=key+(-1948),若要查2023年出生的人數,則只要查第(1970-1948)=22項即可。

由於直接定址所得位址集合和關鍵字集合的大小相同。因此,對於不同的關鍵字不會發生衝突。但實際中能使用這種雜湊函式的情況很少。

[例如],有80個記錄,其關鍵字為8位十進位制數。假設雜湊表的表長為10010,則可取兩位十進位制數組成雜湊位址。取哪兩位?原則是使得到的雜湊位址盡量避免產生衝突,則需從分析這80個關鍵字著手。

對關鍵字全體的分析中我們發現:第①②位都是「8 1」,第③位只可能取1、2、3或4,第⑧位只可能取2、5或7,因此這四位都不可取。由

於中間的四位可看成是近乎隨機的,因此可取其中任意兩位,或取其中兩位與另外兩位的疊加求和後捨去進製作為雜湊位址。

取關鍵字平方後的中間幾位為雜湊位址。這是一種較常用的構造雜湊函式的方法。

通常在選定雜湊函式時不一定能知道關鍵字的全部情況,取其中哪幾位也不一定合適,而乙個數平方後的中間幾位數和數的每一位都相關,由此使隨機分布的關鍵字得到的雜湊位址也是隨機的。取的位數由表長決定。

[例如]:為basic源程式中的識別符號建立乙個雜湊表。假設basic語言中允許的識別符號為乙個字母,或乙個字母和乙個數字。在計算機內可用兩位八進位制數表示字母和數字,假設表長為512=29,則可取關鍵字平方後的中間9位二進位制數為雜湊位址。例如,圖9.23(b)列出了一些識別符號及它們的雜湊位址。 

將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進製)作為雜湊位址,這方法稱為摺疊法(folding)。關鍵字位數很多,而且關鍵字中每一位上數字分布大致均勻時,可以採用摺疊法得到雜湊位址。如國際標準圖書編號0-442-20586-4的雜湊位址分別如

取關鍵字被某個不大於雜湊表表長m的數p除后所得餘數為雜湊位址。即

h(key)=key mod p p≤m

這是一種最簡單,也最常用的構造雜湊函式的方法。它不僅可以對關鍵字直接取模(mod),也可在折迭、平方取中等運算之後取模。值得注意的是,在使用除留餘數法時,對p的選擇很重要。若p選的不好,容易產生同義詞。

由經驗得知:一般情況下可以選p為質數或不包含小於20的質因素的合數。

選擇乙個隨機函式,取關鍵字的隨機函式值為它的雜湊位址,即h(key)=random (key),其中random為隨機函式。通常,當關鍵字長度不等時採用此法構造雜湊函式較恰當。

實際工作中需視不同的情況採用不同的雜湊函式。通常,考慮的因素有:

(1)計算雜湊函式所需時間(包括硬體指令的因素);

(2)關鍵字的長度; 

(3)雜湊表的大小; 

(4)關鍵字的分布情況; 

(5)記錄的查詢頻率。 

雜湊函式可以減少衝突,但不能避免,因此,如何處理衝突是雜湊造表不可缺少的另一方面。

假設雜湊表的位址集為0~(n-1),衝突是指由關鍵字得到的雜湊位址為j(0≤j≤n-1)的位置上已存有記錄,則「處理衝突」就是為該關鍵字的記錄找到另乙個「空」的雜湊位址。在處理衝突的過程中可能得到乙個位址序列hi , i=1,2,…,k, ( hi∈[0,n-1])。即在處理雜湊位址的衝突時,若得到的另乙個雜湊位址h1仍然發生衝突,則再求下乙個位址h2,若h2仍然衝突,再求得h3。依次類推,直至hk不發生衝突為止,則hk為記錄在表中的位址。通常用的處理衝突的方法有下列幾種:

hi=(h(key)+di)mod m         i=1,2,…,k (k≤m-1) (9-25)

其中:h(key)為雜湊函式;m為雜湊表表長;di為增量序列,可有下列三種取法:

(1)di=1,2,3,…,m-1,稱線性探測再雜湊;

(2)di=12,-12,22,-22,33,…,±k2,(k≤m/2)稱二次探測再雜湊;

(3)di=偽隨機數序列,稱偽隨機探測再雜湊。 

[例如],在長度為11的雜湊表中已填有關鍵字分別為17,60,29的記錄(雜湊函式 h(key)=key mod11),現有第四個記錄,其關鍵字為38

從上述線性探測再雜湊的過程中可以看到乙個現象:當表中i,i+1,i+2位置上已填有記錄時,下乙個雜湊位址為i、i+1,i+2和i+3的記錄都將填入j+3的位置,這種在處理衝突過程中發生的兩個第乙個雜湊位址不同的記錄爭奪同乙個後繼雜湊位址的現象稱作「二次聚集」,即在處理同義詞的衝突過程中又新增了非同義詞的衝突,顯然,這種現象對查詢不利。

但另一方面,用線性探測再雜湊處理衝突可以保證做到:只要雜湊表未填滿,總能找到乙個不發生衝突的位址hk,而二次探測再雜湊只有在雜湊表長m為形如 4j+3(j為整數)的素數時才可能,隨機探測再雜湊,則取決於偽隨機數列。

hi=rhi(key) 

rhi均是不同的雜湊函式,即在同義詞產生位址衝突時計算另乙個雜湊函式位址,直到衝突不再發生。這種方法不易產生「聚集」,但增加了計算的時間。 

將所有關鍵字為同義詞的記錄儲存在同一線性鍊錶中。假設某雜湊函式產生的雜湊位址在區間[0..m-1]上,則設立乙個指標型向量chain chainhash[m];其每個分量的初始狀態都是空指標。凡雜湊位址為i的記錄都插入到頭指標為chainhash[i]的鍊錶中。在鍊錶中的插入位置可以在表頭或表尾;也可以在中間,以保持同義詞在同一線性鍊錶中按關鍵字有序。

[例9-3] 已知一組關鍵字為(19,14,23,01,68,20,84,27,55,11,10,79)則按雜湊函式h(key)=key mod13和鏈位址法處理衝突構造所得的雜湊表如圖9.26所示。

這也是處理衝突的一種方法。假設雜湊函式的值域為[0..m-1],則設向量 hashtable[0..m-1]為基本表,每個分量存放乙個記錄,另設立向量overtable[0..v]為溢位表。所有關鍵字和基本表中關鍵字為同義詞的記錄,不管它們由雜湊函式得到的雜湊位址是什麼,一旦發生衝突,都填入溢位表。 

在雜湊表上進行查詢的過程和雜湊造表的過程基本一致。給定k值,根據造表時設定的雜湊函式求得雜湊位址,若表中此位置上沒有記錄,則查詢不成功;否則比較關鍵字,若和給定值相等,則查詢成功;否則根據造表時設定的處理衝突的方法找「下一位址」,直至雜湊表中某個位置為「空」或者表中所填記錄的關鍵字等於給定值時為止。

從雜湊表的查詢過程可見:

1)雖然雜湊表在關鍵字與記錄的儲存位置之間建立了直接映象,但由於「衝突」的產生,使得雜湊表的查詢過程仍然是乙個給定值和關鍵字進行比較的過程。因此,仍需以平均查詢長度作為衡量雜湊表的查詢效率的量度。

2)查詢過程中需和給定值進行比較的關鍵字的個數取決於下列三個因素:雜湊函式,處理衝突的方法和雜湊表的裝填因子。

//開放定址雜湊表的儲存結構

int hashsize = ;//雜湊表容量遞增表,乙個合適的素數序列

typedef structhashtable;

#define success 1

#define unsuccess 0

#define duplicate -1

status searchhash(hashtable h,keytype k, int &p, int &c)

通過呼叫查詢演算法,實現開放定址雜湊表的插入操作

status inserthash(hashtable &h, elemtype e){

//查詢不成功時插入資料元素e到開放定址雜湊表h中,並返回ok;若衝突次數

//過大,則重建雜湊表

c=0;

if(searchhash(h,e.key,p,c))

return duplicate;//表中已有與e有相同關鍵字的元素

else if(c對原作者深表謝意

雜湊表的構造方法以及解決衝突的方法

一 雜湊表是什麼?雜湊表 hash table,也叫雜湊表 是根據關鍵碼值 key value 而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。給定表m,存在函式f key 對任意給定的關鍵字值k...

雜湊函式的構造方法與衝突解決方案

雜湊函式的構造方法 1.直接定值法 取關鍵字或關鍵字的某個線性函式值為雜湊位址。即h key key或h key a key b,其中a和b為常數 這種雜湊函式叫做自身函式 2.除留餘數法 取關鍵字被數p除后所得的餘數為雜湊位址。即 h key key mod p,p m,m表雜湊表的長度 例 h ...

解決雜湊衝突的方法

在實際的應用中,選取合適的雜湊函式可減少衝突,但衝突是不可避免的。所以我就想給大家說幾種解決雜湊衝突的方法啦 首先就是開放定址法,用這個方法處理衝突的核心思想就是在衝突發生的時候,形成乙個位址序列,順著這個序列挨個去檢查探測,一直等到找到乙個 空 的開放位址。把我們發生衝突的關鍵字值存放到這個 空 ...