散列表(雜湊表)
散列表的構造方法
沒有什麼方法對所有情況都是最好的,只有適合的才是最好的
直接定址法
直接定址法就是我們中學學習的函式y = f(x)
,散列表一般使用線性函式,即 f(x) = ax + b
,這種方法很簡單,但是不常用
數字分析法
數字分析法需要根據具體的情況,抽取鍵中的某些值進行計算,比如電話號碼,前三位是接入號,中間四位是歸屬地,最後四位才是使用者編號,如果是統計一個地區的電話號碼,可以只抽取後四位進行計算,數字分析法適合處理關鍵字位數比較大的情況,如果事先知道關鍵字的分佈而且若干位分佈較均勻.可以考慮使用這個方法
平方取中法
這個計算方法很簡單,對關鍵字求平方,然後取出中間的幾位作為雜湊地址,這種方法適合事先不知道關鍵字的分佈,位數又不是很大
摺疊法
摺疊法是將關鍵字從左到右分割成等長的幾部分,然後疊加求和,然後取最後幾位作為雜湊地址,這種方法適合事先不知道關鍵字的分佈,但關鍵字位數很長的情況
除留餘數法
這個方法就是對關鍵字求模,對於散列表長度為m的情況,雜湊函式可以使 f(x) = x mod p (p <= m )
,這個方法的關鍵在於p的值的確定,如果選的不好,那麼會造成很多衝突,不過根據經驗,一般p取小於m的最小質數或不包含小於20質因子的合數.這個方法最為常用
隨機數法
顧名思義,就是選擇關鍵字的隨機數值作為雜湊地址,如果關鍵字長度不等時,採用這個方法比較合適
處理雜湊衝突
雜湊衝突 ,即key1 != key2,但是f(key1) = f(key2)
開放地址法
所謂的開放地址法就是一旦發生了衝突,就去尋找下一個空的雜湊地址,只要雜湊列表足夠大,總能找到
公式為 f(x) = ( f (x) + di ) mod m (di = 1,2,3,4... m-1)
這種方法只是開放地址的其中一種,叫做線性探測法,
還有一種就是二次探測法,公式是:
f (x) = ( f (x) + di ) mod m(di = 1^2 ,-1^2 , 2^2 , -2^2 ...q^2 , - q^2 ,q <= m /2 )
這種方法實現了雙向探測,即如果原來的雜湊地址已經存在其他關鍵字,那麼在這個地址的前後分別探測新的雜湊地址,
當然還有隨機探測,公式和上面的很想,就是把 di 換成一個隨機數
這個方法是常用的解決hash衝突的方法
再雜湊函式法
這種方法就是如果我們通過原來的雜湊函式計算得到的雜湊地址已經被佔,那麼對於這個關鍵字,我們使用另一種雜湊函式計算得到一個新的雜湊地址,以此類推
鏈地址法
這種方法就是如果計算得到的雜湊地址已經被佔領,但是我就要這個位置,那怎麼辦,很簡單,使用連結串列,將散列表每個位置都變成一個連結串列如果發生衝突,就加入到該雜湊地址位置的連結串列的首部即可.
我所知道的,Java的hashmap就是使用這種方法解決hash衝突的
公共溢位區法
這種方法就是將所有發生衝突而沒出呆的關鍵字拿出來,找一個叫公共溢位區的地方,將它們放在哪裡,在進行查詢時,先在原先的散列表中進行查詢,找到相應位置後進行比對,如果比對失敗,再到公共溢位區進行查詢.
這種方法在衝突資料很少的情況下,效能還是很好的.
散列表查詢效能
- 如果在沒有衝突的情況下,散列表查詢的時間複雜度是O(1),但是沒有衝突的散列表只是理想中的,