Set集合底層是基於HashMap的,再準備看Map源碼集合前得有哈希表和紅黑樹相關的數據結構的知識。數組
對哈希表進行了溫習,對知識點作出如下小結 數據結構
1.爲何須要哈希表?Hash函數是幹什麼用的? 函數
2. 哈希碰撞是什麼?哈希碰撞的解決方法有哪些? 性能
3.哈希表的優缺點是什麼?優化
1.爲何須要哈希表?哈希表是什麼?Hash函數是幹什麼用的? 搜索引擎
不管是數組仍是鏈表都對查詢顯得有些無力,要想知道某個元素是否在其中只有從頭至尾進行對比查詢,效率較低。出現這個問題的根源就是咱們沒辦法直接根據一個元素找到它的存儲位置。哈希表便應運而生了。 spa
哈希表(散列表):是經過關鍵碼值(Key)進行訪問的一種數據結構。Key經過特定的哈希函數進行計算映射成一個int數值獲得。 設計
哈希函數就是用來計算獲得特定的int型數值的規則,如數據結構所學到的除留餘數法,直接定址法等 blog
2.解決hash碰撞的方法有哪些?繼承
咱們知道int的值是有限的,它只有2^32^個,經過哈希函數計算後的所獲得的int數值會有重複,此時會產生衝突,即哈希碰撞。解決方法有許多,如二維數組法,開放定址法,數組+鏈表法等
開放地址法:哈希表基本不會像數組同樣每一個位置都有元素,這樣就能夠將碰撞的元素插入到這些空閒的位置中區,這種方案稱爲定址法。有一次線性探測,二次線性探測,這都是數據結構考過的內容,但其可擴展性不佳,且JDK源代碼中也不是使用這種方法解決
二維數組法:即將碰撞的元素按照順序依次存儲起來,但最大的缺點是數組的大小是固定的,因此第二維的數組長度都是同樣的,可是哈希碰撞必定是比較少發生的狀況,也就是咱們聲明瞭一個很大的數組,可是其中大部分都是閒置的,這就浪費了大量的內存。以下圖所示
拉鍊法:目前比較通用的一種方式,數組+鏈表組合的方式。這是當前比較理想的方法,既繼承了數組的優勢,又在碰撞時繼承了鏈表的優勢,這也是哈希表強大的地方之一。當出現哈希碰撞時,在該位置的數據就經過鏈表的方式連接起來,以下圖所示:
在JDK1.7及以前的版本中,HashMap的存儲結構和上圖是一致的,在JDK1.8以後還加入了紅黑樹以進一步優化,以後將對樹,二叉樹,紅黑樹進行整理。
2.哈希碰撞的優缺點
哈希表是一種優化存儲的思想,具體存儲元素的依然是其餘的數據結構。設計良好的哈希表,能同時兼備數組和鏈表的優勢,它能在插入和查找時都具有良好的性能。然而設計很差的哈希表,有可能會出現較多的哈希碰撞,致使鏈表過長,從而哈希表會更像一個鏈表。還有當數據量很大時,爲防止鏈表過長,就須要對數組進行擴容,這時就涉及到了數組的拷貝,其對性能的影響也很嚴重,因此須要提早對可能的狀況有良好的預測,才能真正發揮哈希表的優點。
PS:以上皆爲純理論的知識點,具體的實現代碼須要結合搜索引擎加以練習。後面兩天會去作這方面練習。