散列表
在線性表、樹等數據結構中,記錄在結構中的相對位置是隨機的,和記錄的關鍵字之間不存在確定的關係,因此在結構中查找記錄時需進行一系列和關鍵字的比較。它們查找的效率都依賴於查找過程中所進行的比較次數。
1、散列表的強大
即使是二分查找,查找的時間複雜度也是 O(log2N)。
但是——散列表,理想的情況下有沒有不經過任何比較,一次存取便能得到所查記錄。時間複雜度是 O(1)。
2、散列表的實現
1、使用散列函數將給定鍵轉化爲一個“數組的索引”,數組內可以存儲記錄對應的值,這個函數,我們稱之爲散列(哈希)函數;
2、但對於不同的關鍵字,可能得到同一哈希地址,即k1≠ k2,而f(k1) = f(k2),這種現象我們稱之爲衝突。衝突只能儘可能的少,但是不能完全避免;
2.1 散列函數描述
哈希表的容量一般設置爲素數,因爲無論按照何種步長,總可以遍歷素數。
2.1.1 散列函數特徵
1、相同輸入映射到相同索引;
2、不同輸入映射到不同索引;
3、散列表知道數組多大,只返回有效索引
構造方法:
直接定址法:
Hash(key) = a × key + b
數字分析法:
比如手機號前三位是接入號,中間四位是 HLR 識別號,只有後四位纔是真正的用戶號,此時我們選擇後四位作爲散列地址就是不錯的選擇;
數字分析法通常適合處理關鍵字位數比較大的情況,如果事先知道關鍵字的分佈且關鍵字的若干位分佈較均勻,就可以考慮用這個方法。
平方取中法:
如果事先知道關鍵字的分佈且關鍵字的若干位分佈較均勻,就可以考慮用這個方法
平方取中法比較適合於不知道關鍵字的分佈,而位數又不是很大的情況
摺疊法:
1、將關鍵字從左到右分割成位數相等的幾部分(注意最後一部分位數不夠時可以短些)
2、然後將這幾部分疊加求和
3、按散列表表長,取後幾位作爲散列地址
除留餘數法
Hash(key) = key / a ... b ,b即爲數組地址
隨機數法
2.2衝突處理
2.2.1 拉鍊法
如果多個鍵映射到了同一位置,就在這個位置存儲一個鏈表。
2.2.2 開放地址法
數據項具有相同下標時,在數組中其他地方尋找一個空白單元放置要插入的數據項。
2.2.2.2 線性探測:
在用除留餘數法時:Hi = (Hash(key) + di) mod m di爲增量序列
線性探測中di每次衝突都加1,知道找到空序列;
刪除操作:刪除操作複雜,這裏不進行討論
查找操作:
線性探測是逐步搜索空的位置。缺點:數據項聚集,越來越大,越後面找到空位插入數據項需要時間越多。
2.2.2.3 二次探測法:
Hi = (Hash(key) + di) mod m di爲增量序列
di先後取(±1)2 ,(±2)2,(±3)……
2.2.2.4 僞隨機探測法:
di爲僞隨機數
2.2.3 再散列法(雙散列函數)
2.2.4 建立公共溢出區
3、應用
3.1 DNS解析
如:在訪問像http://adit.io這樣的網站時,計算機必須將adit.io轉換爲IP地址:
ADIT.IO -> 173.255.248.55
無論哪個網站,網址都要轉化爲IP地址:
GOOGLE.COM -> 74.125.239.133
FACEBOOK.COM -> 173.252.120.6
這是將網址映射到IP地址,這過程被成爲DNS解析,散列表是提供這種功能方式之一。
3.2 緩存內放入散列表加快訪問速度
3.3 總結:
散列函數在查找、加密、海量數據處理過程都有強大優勢;
如果在能提前預測數據量的大小。那麼哈希表在速度和易用性方面——無與倫比!!!
缺點:數組創建後難於擴展,某些哈希表被基本填滿時,性能下降得非常嚴重
鏈接: 開放地址法描述.
鏈接: 開放地址法哈希表代碼篇.
鏈接: 散列函數描述.