【Python算法】哈希存儲、哈希表、散列表原理
哈希表的定義:
哈希存儲的基本思想是以關鍵字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 = 12,-12,22,-22 ,...,q2,-q2 (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的實現 是使用開放尋址法中的二次探查來解決沖突的。
?? 參考鏈接
【Python算法】哈希存儲、哈希表、散列表原理