教你幾招HASH表查詢的方法

華為雲開發者社群發表於2021-07-07
摘要:根據設定的雜湊函式 H(key) 和所選中的處理衝突的方法,將一組關鍵字映象到一個有限的、地址連續的地址集 (區間) 上,並以關鍵字在地址集中的“象”作為相應記錄在表中的儲存位置,如此構造所得的查詢表稱之為“雜湊表”。

本文分享自華為雲社群《查詢——HASH》,原文作者:ruochen。

對於頻繁使用的查詢表,希望 ASL = 0
記錄在表中位置和其關鍵字之間存在一種確定的關係

HASH

定義

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

HASH函式的構造

  • 構造原則
    • 函式本身便於計算
    • 計算出來的地址分佈均勻,即對任一關鍵字k,f(k) 對應不同地址的概率相等,目的是儘可能減少衝突

直接定址法

  • 雜湊函式為關鍵字的線性函式
    • H(key) = key
    • H(key) = a * key + b

 

  • 此法僅適合於:
    地址集合的大小 = = 關鍵字集合的大小
  • 優點:以關鍵碼key的某個線性函式值為雜湊地址,不會產生衝突
  • 缺點:要佔用連續地址空間,空間效率低

教你幾招HASH表查詢的方法

數字分析法

  • 假設關鍵字集合中的每個關鍵字都是由 s 位數字組成 (u1, u2, …, us),分析關鍵字集中的全體, 並從中提取分佈均勻的若干位或它們的組合作為地址
  • 此方法僅適合於:
    能預先估計出全體關鍵字的每一位上各種數字出現的頻度

教你幾招HASH表查詢的方法

平方取中法

  • 以關鍵字的平方值的中間幾位作為儲存地址。求“關鍵字的平方值” 的目的是“擴大差別” ,同時平方值的中間各位又能受到整個關鍵字中各位的影響
  • 此方法適合於:
    關鍵字中的每一位都有某些數字重複出現頻度很高的現象

教你幾招HASH表查詢的方法

摺疊法

  • 將關鍵字分割成若干部分,然後取它們的疊加和為雜湊地址。有兩種疊加處理的方法:移位疊加和間界疊加
  • 此方法適合於:
    關鍵字的數字位數特別多

教你幾招HASH表查詢的方法

除留餘數法

  • Hash(key)=key mod p (p是一個整數)
    • p≤m (表長)
    • p 應為小於等於 m 的最大素數

為什麼要對 p 加限制?

給定一組關鍵字為: 12, 39, 18, 24, 33, 21若取 p=9, 則他們對應的雜湊函式值將為:
3, 3, 0, 6, 6, 3

可見,若 p 中含質因子 3, 則所有含質因子 3 的關鍵字均對映到“3 的倍數”的地址上,從而增加了“衝突”的可能

教你幾招HASH表查詢的方法

隨機數法

  • H(key) = Random(key) (Random 為偽隨機函式)
  • 此方法用於對長度不等的關鍵字構造雜湊函式

考慮因素

  1. 執行速度(即計算雜湊函式所需時間)
  2. 關鍵字的長度
  3. 雜湊表的大小
  4. 關鍵字的分佈情況
  5. 查詢頻率

採用何種構造雜湊函式的方法取決於建表的關鍵字集合的情況
原則是使產生衝突的可能性降到儘可能地小

處理衝突的方法

1. 開放定址法

基本思想

  • 有衝突時就去尋找下一個空的雜湊地址,只要雜湊表足夠大,空的雜湊地址總能找到,並將資料元素存入

線性探測法

  • Hi=(Hash(key)+di) mod m ( 1≤i < m )
    其中:m為雜湊表長度
    di 為增量序列 1,2,…m-1,且di=i

一旦衝突,就找下一個空地址存入

教你幾招HASH表查詢的方法

  • 優點:只要雜湊表未被填滿,保證能找到一個空地址單元存放有衝突的元素
  • 缺點:能使第i個雜湊地址的同義詞存入第i+1個地址,這樣本應存入第i+1個雜湊地址的元素變成了第i+2個雜湊地址的同義詞,……,產生“聚集”現象,降低查詢效率

二次探測法

di = 12, -12, 22, -22, …±k2

教你幾招HASH表查詢的方法

偽隨機探測法

Hi=(Hash(key)+di) mod m ( 1≤i < m )
其中:m為雜湊表長度
di 為隨機數

開放定址法建立雜湊表步驟

  • 取資料元素的關鍵字key,計算其雜湊函式值(地址)。若該地址對應的儲存 空間還沒有被佔用,則將該元素存入;否則執行step2解決衝突
  • 根據選擇的衝突處理方法,計算關鍵字key的下一個儲存地址。若下一個儲存地址仍被佔用,則繼續執行step2,直到找 到能用的儲存地址為止

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

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

int hashsize[] = {997, ...};
typedef struct{
    ElemType* elem;
    int count;  // 當前資料元素個數
    int sizeindex;  // hashsize[sizeindex]為當前容量
} HashTable;

#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1

Status SearchHash(HashTable H, KeyType K, int &p, int &c){
    // 在開放定址雜湊表H中查詢關鍵碼為K的記錄
    p = Hash(K);  // 求得雜湊地址
    while(H.elem[p].key != NULLKEY && !EQ(K, H.elem[p].key))
        collisiion(p, ++c);  // 求得下一探測地址p
    if(EQ(K, H.elem[p].key)) return SUCCESS;  // 查詢成功,返回待查資料元素位置 p
    else return UNSUCCESS;  // 查詢不成功
}

2. 再HASH法

  • H2(key) 是另設定的一個雜湊函式,它的函式值應和 m 互質

教你幾招HASH表查詢的方法

3. 鏈地址法

基本思想

  • 相同雜湊地址的記錄鏈成一單連結串列,m個雜湊地址就設m個單連結串列,然後用用一個陣列將m個單連結串列的表頭指標儲存起來,形成一個動態的結構

教你幾招HASH表查詢的方法

優點:

  • 非同義詞不會衝突,無“聚集”現象
  • 連結串列上結點空間動態申請,更適合於表長不確定的情況

雜湊表的查詢

對於給定值 K,計算雜湊地址 i = H(K)

  • 若 r[i] = NULL 則查詢不成功
  • 若 r[i].key = K 則查詢成功, 否則 “求下一地址 Hi” ,直至r[Hi] = NULL (查詢不成功) 或r[Hi].key = K (查詢成功) 為止

教你幾招HASH表查詢的方法

案例v01

  • 線性探測法解決衝突

教你幾招HASH表查詢的方法

案例v02

  • 鏈地址法處理衝突

教你幾招HASH表查詢的方法

雜湊表查詢的分析

從查詢過程得知,雜湊表查詢的平均查詢長度實際上並不等於零

決定雜湊表查詢的ASL的因素

  • 選用的雜湊函式
  • 選用的處理衝突的方法
  • 雜湊表飽和的程度,裝載因子 α=n/m 值的大小(n—記錄數,m—表的長度)

α 越大,表中記錄數越多,說明表裝得越滿,發生衝突的可能性就越大,查詢時比較次數就越多

教你幾招HASH表查詢的方法

  1. 對雜湊表技術具有很好的平均效能,優於一些傳統的技術
  2. 鏈地址法優於開地址法
  3. 除留餘數法作雜湊函式優於其它型別函式

雜湊表應用舉例

編譯器對識別符號的管理多是採用雜湊表

  • 構造雜湊函式的方法
    • 將識別符號中的每個字元轉換為一個非負整數
    • 將得到的各個整陣列合成一個整數(可以將第一個、中間的和最後一個字元值加在一起,也可以將所有字元的值加起來)
    • 將結果數調整到0~M-1範圍內,可以利用取模的方法,Ki%M(M為素數)

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章