雜湊儲存、雜湊表原理
雜湊表的定義
雜湊儲存的基本思想是以關鍵字Key為自變數,通過一定的函式關係(雜湊函式或雜湊函式),計算出對應的函式值(雜湊地址),以這個值作為資料元素的地址,並將資料元素存入到相應地址的儲存單元中。
查詢時再根據要查詢的關鍵字採用同樣的函式計算出雜湊地址,然後直接到相應的儲存單元中去取要找的資料元素即可。
雜湊表的應用
雜湊表(hash table)是實現字典操作的一種有效的資料結構。
儘管最壞的情況下,散列表中查詢一個元素的時間與連結串列中查詢的時間相同,達到了O(n)。然而實際應用中,雜湊的查詢的效能是極好的。在一些合理的假設下,在散列表中查詢一個元素的平均時間是O(1)。
建立雜湊表操作步驟
1) step1 取資料元素的關鍵字key,計算其雜湊函式值(地址)。若該地址對應的儲存空間還沒有被佔用,則將該元素存入;否則執行step2解決衝突。
2) step2 根據選擇的衝突處理方法,計算關鍵字key的下一個儲存地址。若下一個儲存地址仍被佔用,則繼續執行step2,直到找到能用的儲存地址為止。
常用的雜湊函式
構造雜湊函式的方法有很多,總的原則是儘可能將關鍵字集合空間均勻的對映到地址集合空間中,同時儘可能降低衝突發生的概率。
1、除留餘數法:
H(Key) = key % p (p ≤ m)
取關鍵字除以p的餘數作為雜湊地址,p最好選擇一個小於或等於m(雜湊地址集合的個數)的某個最大素數
雜湊表長度 | 8 | 16 | 32 | 64 | 128 | 256 | 512 |
---|---|---|---|---|---|---|---|
最大素數 | 7 | 13 | 31 | 61 | 127 | 251 | 503 |
2、直接地址法
H(Key) = a * Key + b;這個“a,b”是常量。
3、數字分析法
比如有一組key1=112233,key2=112633,key3=119033,
針對這樣的數我們分析數中間兩個數比較波動,其他數不變。那麼我們取key的值就可以是 key1=22,key2=26,key3=90。
4、平方取中法
此處忽略,見名識意。
5、摺疊法
比如key=135790,要求key是2位數的雜湊值。那麼我們將key變為13+57+90=160,然後去掉高位“1”,此時key=60,
以上五種雜湊關係的目的就是地址與每一位的key都相關,來做到“雜湊地址”儘可能分散。
衝突處理方法
我們知道影響雜湊查詢效率的一個重要因素是雜湊函式本身。當兩個不同的資料元素的雜湊值相同時,就會發生衝突。為減少發生衝突的可能性,雜湊函式應該將資料儘可能分散地對映到雜湊表的每一個表項中。
解決衝突的方法有以下兩種:
(1) 開放地址法
如果兩個資料元素的雜湊值相同,則在雜湊表中為後插入的資料元素另外選擇一個表項。
當程式查詢雜湊表時,如果沒有在第一個對應的雜湊表項中找到符合查詢要求的資料元素,程式就會繼續往後查詢,直到找到一個符合查詢要求的資料元素,或者遇到一個空的表項。
①.線性探測法
這種方法在解決衝突時,依次探測下一個地址,直到有空的地址後插入,若整個空間都找遍仍然找不到空餘的地址,產生溢位。
Hi =( H(Key) + di ) % m ( i = 1,2,3,...,k , k ≤ m-1 )
地址增量 di = 1,2,...,m-1 , 其中 i 為探測次數
②.二次探測法
地址增量序列為:di = 1^2,-1^2,2^2,-2^2 ,...,q^2,-q^2 (q ≤ m/2)
③.雙雜湊函式探測法
Hi =( H(Key) + i * RH(Key) ) % m ( i = 1,2,3,..., m-1 )
H(Key) , RH(Key) 是兩個雜湊函式,m為雜湊表長度。
先用第一個雜湊函式對關鍵字計算雜湊地址,一旦產生地址衝突,再用第二個函式確定移動的步長因子,最後通過步長因子序列由探測函式尋找空餘的雜湊地址。
H1 = ( a+b )%m , H2 = ( a + 2b )%m , ... , Hm-1 = ( a+(m-1)*b )%m
(2) 鏈地址法
將雜湊值相同的資料元素存放在一個連結串列中,在查詢雜湊表的過程中,當查詢到這個連結串列時,必須採用線性查詢方法。
Python字典dict的實現是使用開放定址法中的二次探查來解決衝突的。