HashMap 和 HashSet 即 java 中利用哈希表實現的 Map 和 Set

Java中的HashTable 哈希表
一:概念

順序結構以及平衡樹中,元素關鍵碼與其存儲位置之間沒有對應的關係,所以在查找一個元素時,必需要通過關鍵碼的屢次比較。順序查找時間複雜度爲O(N),平衡樹中爲樹的高度,即O(log_2 N),搜索的效率取決於搜索過程當中元素的比較次數。
理想的搜索方法:能夠不通過任何比較,一次直接從表中獲得要搜索的元素。 若是構造一種存儲結構,經過某種函數使元素的存儲位置與它的關鍵碼之間可以創建一一映射的關係,那麼在查找時經過該函數能夠很快找到該元素。
當向該結構中:
插入元素
根據待插入元素的關鍵碼,以此函數計算出該元素的存儲位置並按此位置進行存放。
搜索元素
對元素的關鍵碼進行一樣的計算,把求得的函數值當作元素的存儲位置,在結構中按此位置取元素比較,若關鍵碼相等,則搜索成功。
該方式即爲哈希(散列)方法,哈希方法中使用的轉換函數稱爲哈希(散列)函數,構造出來的結構稱爲哈希表(HashTable)(或者稱散列表)
二: 衝突-概念
對於兩個數據元素的關鍵字K1!=K2,但有:Hash(K1) == Hash(K2),即:不一樣關鍵碼經過相同哈希函數計算出相同的哈希地址,該種現象稱爲哈希衝突或哈希碰撞。
把具備不一樣關鍵碼而具備相同哈希地址的數據元素稱爲「同義詞」。
三:衝突-避免-設計哈希函數
引發哈希衝突的一個緣由多是:哈希函數設計不夠合理。 哈希函數設計原則:
1.哈希函數的定義域必須包括須要存儲的所有關鍵碼,而若是散列表容許有m個地址時,其值域必須在0到m-1之間。
2.哈希函數計算出來的地址能均勻分佈在整個空間中。
3.哈希函數應該比較簡單。
常見哈希函數有:java

  1. 直接定製法--(經常使用)
    取關鍵字的某個線性函數爲散列地址:Hash(Key)= A*Key + B
    優勢:簡單、均勻
    缺點:須要事先知道關鍵字的分佈狀況
    使用場景:適合查找比較小且連續的狀況 ide

  2. 除留餘數法--(經常使用)
    設散列表中容許的地址數爲m,取一個不大於m,但最接近或者等於m的質數p做爲除數,按照哈希函數:Hash(key) = key% p(p<=m),將關鍵碼轉換成哈希地址。
  3. 平方取中法--(瞭解) 摺疊法--(瞭解)隨機數法--(瞭解)數學分析法--(瞭解)。
    四:衝突-避免-設計哈希函數HashMap 和 HashSet 即 java 中利用哈希表實現的 Map 和 Set

五: 衝突-解決
解決哈希衝突兩種常見的方法是:閉散列(線性探測法)和開散列(拉鍊桶)
六:(1)衝突-解決-閉散列
閉散列:也叫開放定址法,當發生哈希衝突時,若是哈希表未被裝滿,說明在哈希表中必然還有空位置,那麼能夠把key存放到衝突位置中的「下一個」 空位置中去。那如何尋找下一個空位置呢?
線性探測:從發生衝突的位置開始,依次向後探測,直到尋找到下一個空位置爲止。
插入:
經過哈希函數獲取待插入元素在哈希表中的位置,若是該位置中沒有元素則直接插入新元素,若是該位置中有元素髮生哈希衝突,使用線性探測找到下一個空位置,插入新元素。
採用閉散列處理哈希衝突時,不能隨便物理刪除哈希表中已有的元素,若直接刪除元素會影響其餘元素的搜索。好比刪除元素4,若是直接刪除掉,44查找起來可能會受影響。所以線性探測採用標記的僞刪除法來刪除一個元素。
可是:閉散列最大的缺陷就是空間利用率比較低,這也是哈希的缺陷。函數

六:(2)衝突-解決-開散列/哈希桶(重點)
開散列法又叫鏈地址法(開鏈法),首先對關鍵碼集合用散列函數計算散列地址,具備相同地址的關鍵碼歸於同一子集合,每個子集合稱爲一個桶,各個桶中的元素經過一個單鏈表連接起來,各鏈表的頭結點存儲在哈希表中。
HashMap 和 HashSet 即 java 中利用哈希表實現的 Map 和 Set性能

從上圖能夠看出,開散列中每一個桶中放的都是發生哈希衝突的元素。
開散列,能夠認爲是把一個在大集合中的搜索問題轉化爲在小集合中作搜索了。設計

七:性能分析
雖然哈希表一直在和衝突作鬥爭,但在實際使用過程當中,咱們認爲哈希表的衝突率是不高的,衝突個數是可控的,也就是每一個桶中的鏈表的長度是一個常數,因此,一般意義下,咱們認爲哈希表的插入/刪除/查找時間複雜度是O(1) 。
八:和 java 類集的關係對象

  1. HashMap 和 HashSet 即 java 中利用哈希表實現的 Map 和 Set
  2. java 中使用的是哈希桶方式解決衝突的
  3. java 會在衝突鏈表長度大於必定閾值後,將鏈表轉變爲搜索樹(紅黑樹)
  4. java 中計算哈希值其實是調用的類的 hashCode 方法,進行 key 的相等性比較是調用 key 的 equals 方法。因此若是要用自定義類做爲 HashMap 的 key 或者 HashSet 的值,必須覆寫 hashCode 和 equals 方 法,並且要作到 equals 相等的對象,hashCode 必定是一致的。
相關文章
相關標籤/搜索