哈希表定義:
根據設定的哈希函數H(key)和處理沖突的方法將一組關鍵字映像到一個有限的連續的地址集(區間)上,并以關鍵字在地址集中的“像”作為記錄在表中的位置,這種表便稱為哈希表,這一映像過程稱為哈希造表或散列,所得到存儲位置稱哈希地址或散列地址。
前言
在順序查找、二分查找、斐波那契查找、插值查找、最優(次優)查找樹、二叉排序樹、二叉平衡樹、B-樹等查找方法中,記錄的位置相對是隨機的,在查找記錄時依賴與關鍵字的比較(有><=三種情況)。因此以上查找的效率依賴查找過程中進行比較的次數。
若能將所查記錄與其存儲位置建立一個對應關系f,使每個記錄中關鍵字與其存儲位置一一對應,則在查找時只需查看在其對應存儲位置有無包含所查關鍵字的記錄即可。
我們稱上述對應關系f為“哈希(Hash)函數”。按照這個思想建立的表為哈希表。
對于不同關鍵字可能得到相同的哈希地址,即key1!=key2,而f(key1)==f(key2),這種現象成為沖突(collision)。具有相同哈希值的關鍵字稱為同義詞(synonym)。在一般情況下,沖突只能盡可能的減少而不能完全避免(哈希函數是一個壓縮映像)。因此在建造哈希表時,不僅要設定一個“好”的哈希函數,而且要設定一種處理沖突的辦法。
哈希函數構造方法
1、直接定址法
取關鍵字或關鍵字的某個線性函數值作為哈希地址。即H(key)=key或者H(key)=a×key+b。
直接定址法所得的地址集與關鍵字集合大小相同,不同關鍵字不會產生沖突。
2、數字分析法
假設關鍵字都是事先知道的,則可取關鍵字的若干數位組成哈希地址。
3、平方取中法
取關鍵字平方后的中間幾位作為哈希地址。一個數平方后的中間幾位數和數的每一位都相關,由此隨機分布的關鍵字得到的哈希地址也是隨機的,取的位數由表長決定。
4、折疊法
將關鍵字分割成位數相同的幾部分(最后一部分位數也可以不同),然后取這幾部分的疊加和(舍去進位)作為哈希地址。
關鍵字位數很多,而且關鍵字的每一位上數字分布大致均勻時可以采用此法。
5、除留余數法
取關鍵字被某個不大于哈希表長m的數p除后所得余數為哈希地址。即H(key)=key MOD p,p<=m;
可以對關鍵字直接取模,也可以在折疊,平方運算之后取模。
但是,在使用此法時,對p的選擇很重要。若p選的不好,容易產生同義詞。
一般情況下,可以選p為質數或不包含小于20的質因子的合數。
6、隨機數法
選擇一個隨機函數,取關鍵字的隨機函數值作為它的哈希地址,即H(key)=Random(key)。通常,關鍵字長度不等時采用此法構造哈希函數較為恰當。
處理沖突的方法
1、開放定址法
Hi=(H(key)+di) MOD m,i=1,2,3,...,k(k<=m-1)
其中:H(key)為哈希函數;m為哈希表表長;di為增量序列有三種取法:di=1,2,3,...,m-1,稱線性探測再散列;di=12,-12,22,-22,...,+-k2,(k<=m/2)稱二次探測再散列;di=偽隨機數序列,稱偽隨機探測再散列。
2、再哈希法
Hi=RH(key) i=1,2,3,...,k
3、鏈地址法
將所有關鍵字同義詞存儲在同一線性鏈表中。
4、建立公共溢出區
哈希表的查找及其分析
在哈希表上查找過程和建造哈希表過程基本一致。若查找位置上沒有記錄則查找不成功,否則比較關鍵字,若和給定值相等,則查找成功,否則根據建表時設定的處理沖突的方法找“下一地址”,直至哈希表某個位置為“空”或者表中所填記錄關鍵字等于給定值時為止。
int hashsize[]={997,...}; //哈希表容量遞增表,一個合適的素數序列。
typedef struct{
ElemType *elem;
int count;
int sizeindex;
}HashTable;
\#define SUCCESS 1
\#define USUCCESS 0
\#define DUPLICATE -1
Status SearchHash(HashTable H,KeyType K,int &p,int &c){
//若查找成功返回SUCCESS,p指示待查元素在表中的位置,否則返回UNSUCCESS,p指示插入位置。
//c用來記錄沖突次數
p=Hash(K);
while(H.elem[p].key!=NULLKEY&&!EQ(K,H.elem[p].key)
collision(p,++c);
if EQ(K,H.elem[p].key)
return SUCCESS;
else return UNSUCCESS;
}//SearchHash
Status InsertHash(HashTable &H,Elemtype e){
c=0;
if(SearchTable(H,e.key,p,c))
return DUPLICATE;
else if(c<hashsize[H.sizeindex]/2){
H.elem[p]=e;
++H.count;
return OK;
}
else{RecreateHashTable(H); return UNSUCCESS;}
}//InsertHash
由于沖突的產生,使得哈希表的查找過程仍然是一個給定值和關鍵字比較的過程。因此要以平局查找長度為衡量哈希表查找效率的度量。
在查找過程中需和關鍵字比較的個數取決于
1.哈希函數
2.處理沖突的方法
3.哈希表的裝填因子
在線性探測再序列中易產生記錄的二次聚集,即對于哈希地址不同的 關鍵字產生沖突;鏈地址法則不會產生類似情況。
裝填因子越大表示哈希表的裝滿程度,裝填因子越小,發生沖突的概率越小,平均查找長度越小。
哈希表的平均查找長度是裝填因子的函數,而不是表長n的函數,可以選擇一個合適的裝填因子使平均查找長度限定在一個范圍內。而對于非鏈地址處理沖突的哈希表中刪除一個記錄,需在該記錄位置填一個特殊符號,以免找不到在它之后填入的同義詞。