文章目錄
散列方法
哈系表有 m 個槽,如何將關鍵字 key 散列到哈系表的槽中呢?
除法散列方法散列結果由下列散列函數決定:
hash(key) mod m
其中 m 是 hash 表的大小,注意 m 的選擇:
(1) m 不應是 2 的冪。原因分析如下:
散列的發散程度取決於 hash(key) mod m 的分布範圍,
假設 m = 2^p, 對 m 取餘,結果等於哈系值中二進位的最低 p 位,
如果雜湊值最低 p 位的排列很相似,則 hash(key) mod m 的分布
範圍很小,關鍵字的發散程度就不夠好。
(2) 經驗表明, 取 m 為與 2 的整數冪不太接近的素數。
可以選擇與 [ 2^p + 2^(p+1) ] /2 最接近的一個素數。
一個經典的哈系函數
不斷地乘以 33, 至於為什麼選擇 33, 還沒足夠充分的解釋,經驗所得。
unsigned long hash(unsigned char *str){ unsigned long value = 5381; unsigned char *p; for (p = str; *p; p++) { value = (value << 5) + value + *p; } return value;}
處理衝突的方法
連結法
把散列到同一槽中的所有元素都放在一個鏈表中。如果 hash 表有 n 個元素,m 個槽。
則一個鏈中平均儲存的元素數,即裝載因子 a = n/m ,連結法中裝載因子可能大於 1。
最壞情況下,n 個元素都散列到同一個鏈表,這時尋找事件為 O(n)。
平均情況下,尋找時間為 O(1+a)
開放定址法
所有的元素都存放在散列表裡,尋找一個元素時,計算出該關鍵字對應的槽,從這個槽開始,
按照一定的順序探查所有的表項,直到找到所需的元素為止,開放定址法的裝載因子 a 絕對小於 1。
插入一個元素時,先計算該關鍵字對應的槽,按照一定的順序探查所有表項,直到找到一個空位為止。
在開放定址法中,尋找和插入都要探查很多槽,對每一個關鍵字,都存在一個長度為 m 的探查序列,設為:
< h(k, 0), h(k, 1), ... , h(k, m-1) >
理想情況下,探查序列有 m! 種,每個關鍵字的探查序列是 < 0, 1, ..., m-1 > 的 m! 中排列中
任意一種的可能性是相同的,這稱為一致散列。但真正的一致散列很難實現,在實踐中,
有三種技術常用來計算開放定址法中的探查序列: 線性探查,二次探查,和雙重探查。
(1) 線性探查
初始探查位置為 t,下一個探查位置為 t+1,再下一個探查 t+2,..., 依次類推,直到 m-1,
然後又卷繞到 0, 1, ..., 直到最後探查槽 t-1。 散列函數為:
h(k, i) = ( h(k) + i ) mod m
線上性探查序列中,一旦確定了初始探查位置,後面的探查位置都固定下來了,
初始探查位置決定了整個序列,而初始探查位置有 m 種,故只有 m 種不同的探查序列。
線性探查方法比較容易實現,但容易出現群集現象,例如: 假設某個時刻,槽
T[k+1] 到 T[k+i] 都被連續佔用了,如所示:
在這種情況下,下一個插入的關鍵字,只要其計算出來的初始位置位於區間 [ k+1, k+i+1 ] ,
槽 T[k+i+1] 都會被使用,即槽 T[k+i+1] 被佔用的機率為 (i+1)/m。槽 T[k+i+1] 的使用導致
連續佔用槽的序列長度增加,引起下一個槽 T[k+i+2] 被使用的機率變得更大。這樣惡性迴圈
下去。連續被佔用槽的長度不斷增加,尋找和插入時間的探查時間也不斷增加。這被稱為
群集現象。
(2) 二次探查
散列函數為:
h(k, i) = ( h(k) + c1*i + c2* i^2 ) mod m
初始探查位置為 T[ h(k) ], 後續的探查位置在此基礎上加上一個位移,該位移以二次的方式依賴於 i,
二次探查的效果比一次探查好很多,不過與線性探查一樣,初始探查位置決定了整個序列,故只有
m 種不同的探查序列。這會導致一種程度較輕的群集現象,稱為二次群集。
(3) 雙重散列
雙重散列是開放定址法中最好的探查方法,其散列函數為:
h(k, i) = [ h(k) + i*h'(k) ] mod m
其中 h'(k) 是輔助散列函數。
為了能尋找整個散列表,值 h'(k) 要與表的大小 m 互質(結論的證明要利用數論
的知識),確保這個性質的一種方法是令 m 為一個質數,並讓 h'(k) 總是產生比
m 小的雜湊值。
在雙重散列法中,一旦確定了 h(k) 和 h'(k),則關鍵字 k 的探查序列就確定下來。
所以一個探查序列由 組合< h(k) , h'(k) > 共同決定,對 m 取餘數,h(k) 可以產生 m 種
探查序列, h'(k) 也可以產生 m 種探查序列,所以雙重散列法可以產生 O(m^2) 種
探查序列。比線性探查和二次探查有很大的提高。