上一章咱們講了如何根據須要動態設置hash表
的大小,在第四章中,咱們使用了雙重哈希
來解決hash表
的碰撞,其實解決方法有不少,這一章咱們來介紹下其餘方法。segmentfault
本章將介紹兩種解決hash表
碰撞的方法:緩存
使用拉鍊法,每個bucket
都會包含一個連接表
,當發生碰撞
時,就會將該記錄插入在該位置的連接表
後面,步驟以下:函數
hash函數
獲取到要插入的位置,若是該位置是空的,就直接插入,若是該位置不是空的,就插入在連接表
的後面hash函數
獲取到key
對應的位置,遍歷連接表
,判斷key
是否是搜索的key
,若是是,則返回value
,不然返回NULL
hash函數
獲取到key
對應的位置,遍歷連接表
,找到須要刪除的key
,若是找到,則將該key
對應的記錄從連接表
中刪除,若是連接表
中只有一條記錄,則將該位置置爲NULL
拉鍊法的優勢是實現起來簡單,可是空間利用率低。每一個記錄必須存儲指向連接表
中下一個記錄的指針,若是沒有記錄,則指向NULL
,這種方法會浪費一些空間來存儲額外的指針。性能
開放地址法能解決拉鍊法空間利用率低的問題,發生碰撞時,碰撞的記錄將放置在hash表
中的其餘bucket
中,存放的位置是根據預先肯定的規則選擇的,以便在搜索記錄時能夠重複該規則,有以下幾種規則:spa
當發生碰撞
時,就會遞增索引,將記錄插入在下一個可用的索引中,方法以下:指針
hash函數
找到插入的位置的索引,若是這個位置是空的,直接插入,若是不爲空,就遞增索引,直到找到索引指向的位置是空的爲止,而後執行插入hash函數
找到搜索的記錄的索引,每次遞增索引,並比較索引指向的值是不是要搜索的值,若是索引指向的是空,則返回NULL
hash函數
找到刪除的記錄的索引,每次遞增索引,直到找到要刪除的那個key
後執行刪除線性探測提供了良好的緩存性能,可是存在碰撞後遍歷次數多的問題。將發生碰撞
的key
放入下一個可用的bucket
中可能致使後面插入記錄也要日後插,就須要屢次迭代。code
二次探查法和先行探查相似,不一樣的是,發生碰撞
後,咱們會將記錄插入在以下的序列中:i, i + 1, i + 4, i + 9, i + 16, ...
,i
表明經過hash函數
獲取到的索引,具體步驟以下:教程
hash函數
找到插入的索引,經過遍歷上面的序列直到找到一個空的或已被刪除的索引位置,執行插入hash函數
找到key
的索引,遍歷上面的序列,將序列上的key
與搜索的key
對比,若是相等,則返回value
,不然返回NULL
碰撞鏈
上的,因此咱們不能直接刪除該條記錄,只能把它標記爲已刪除
二次探查法減小發生碰撞
後遍歷的次數,而且仍然提供了不錯的緩存性能。索引
hash
雙重hash
旨在解決碰撞後遍歷次數多的問題。使用兩次hash函數
爲插入的記錄選擇新的索引,這個索引會均勻的分佈在整個表中,該方法雖然解決了上述問題,但也失去了緩存特性,雙重hash
是實際項目中常見的衝突管理方法,也是咱們在本教程中實現的方法。get
上一章:設置hash表
大小