1、HashMap
一、基於哈希表的 Map 接口的實現。此實現提供全部可選的映射操做,並容許使用 null 值和 null 鍵。(除了非同步和容許使用 null 以外,HashMap 類與 Hashtable 大體相同。)此類不保證映射的順序,特別是它不保證該順序恆久不變。
二、HashMap 的實例有兩個參數影響其性能:初始容量 和加載因子。容量是哈希表中桶的數量,初始容量只是哈希表在建立時的容量。加載因子是哈希表在其容量自動增長以前能夠達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,則要對該哈希表進行rehash 操做(即重建內部數據結構),從而哈希表將具備大約兩倍的桶數。
按照key關鍵字的哈希值和buckets數組的長度取模查找桶的位置,若是key的哈希值相同,Hash衝突(也就是指向了同一個桶)則每次新添加的做爲頭節點,而最早添加的在表尾。
HashMap中的桶的個數就是下圖中的0- n的數組的長度,存儲第一個entry的位置叫‘桶(bucket)’而桶中只能存一個值也就是鏈表的頭節點,鏈表的每一個節點就是添加的一個值(HashMap內部類Entry的實例Entry有哪些屬性以後在詳說),也能夠這樣理解,一個entry 類型的存儲鏈表的數組。數組的索引位置就是一個個桶的索引地址。
從上圖咱們能夠發現哈希表是由數組+鏈表組成的,一個長度爲16的數組中,每一個元素存儲的是一個鏈表的頭結點。那麼這些元素是按照什麼樣的規則存儲到數組中呢。通常狀況是經過hash(key)%len得到,也就是元素的key的哈希值對數組長度取模獲得。好比上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。因此十二、2八、108以及140都存儲在數組下標爲12的位置。
HashMap簡單總結:
一、HashMap 是鏈式數組(存儲鏈表的數組)實現查詢速度能夠,並且能快速的獲取key對應的value;
二、查詢速度的影響因素有 容量和負載因子,容量大負載因子小查詢速度快但浪費空間,反之則相反;
三、數組的index值是(key 關鍵字, hashcode爲key的哈希值, len 數組的大小):hashcode%len的值來肯定,若是容量大負載因子小則index相同(index相同也就是指向了同一個桶)的機率小,鏈表長度小則查詢速度快,反之index相同的機率大鏈表比較長查詢速度慢。
四、對於HashMap以及其子類來講,他們是採用hash算法來決定集合中元素的存儲位置,當初始化HashMap的時候系統會建立一個長度爲capacity的Entry數組,這個數組裏能夠存儲元素的位置稱爲桶(bucket),每個桶都有其指定索引,系統能夠根據索引快速訪問該桶中存儲的元素。
五、不管什麼時候HashMap 中的每一個桶都只存儲一個元素(Entry 對象)。因爲Entry對象能夠包含一個引用變量用於指向下一個Entry,所以可能出現HashMap 的桶(bucket)中只有一個Entry,但這個Entry指向另外一個Entry 這樣就造成了一個Entry 鏈。
六、經過上面的源碼發現HashMap在底層將key_value對當成一個總體進行處理(Entry 對象)這個總體就是一個Entry對象,當系統決定存儲HashMap中的key_value對時,徹底沒有考慮Entry中的value,而僅僅是根據key的hash值來決定每一個Entry的存儲位置。
JDK1.8中使用一個Node數組來存儲數據,但這個Node多是鏈表結構,也多是紅黑樹結構若是插入的key的hashcode相同,那麼這些key也會被定位到Node數組的同一個格子裏。算法
若是同一個格子裏的key不超過8個,使用鏈表結構存儲。若是超過了8個,那麼會調用treeifyBin函數,將鏈表轉換爲紅黑樹。那麼即便hashcode徹底相同,因爲紅黑樹的特色,查找某個特定元素,也只須要O(log n)的開銷數組
也就是說put/get的操做的時間複雜度最差只有O(log n)。數據結構
須要注意:key的對象,必須正確的實現了Compare接口函數
2、TreeMap
紅黑樹是一種近似平衡的二叉查找樹,它可以確保任何一個節點的左右子樹的高度差不會超過兩者中較低那個的一陪。具體來講,紅黑樹是知足以下條件的二叉查找樹(binary search tree):性能
-
每一個節點要麼是紅色,要麼是黑色。code
-
根節點必須是黑色對象
-
紅色節點不能連續(也便是,紅色節點的孩子和父親都不能是紅色)。blog
-
對於每一個節點,從該點至null(樹尾端)的任何路徑,都含有相同個數的黑色節點。排序
在樹的結構發生改變時(插入或者刪除操做),每每會破壞上述條件3或條件4,須要經過調整使得查找樹從新知足紅黑樹的條件。索引
二、TreeMap的底層使用了紅黑樹來實現,像TreeMap對象中放入一個key-value 鍵值對時,就會生成一個Entry對象,這個對象就是紅黑樹的一個節點,其實這個和HashMap是同樣的,一個Entry對象做爲一個節點,只是這些節點存放的方式不一樣。
三、存放每個Entry對象時都會按照key鍵的大小按照二叉樹的規範進行存放,因此TreeMap中的數據是按照key從小到大排序的。
TreeMap總結:
程序添加新節點時,老是從樹的根節點開始比較,即將根節點當成當前節點。若是新增節點大於當前節點而且當前節點的右節點存在,則以右節點做爲當前節點,若是新增節點小於當前節點而且當前節點的左子節點存在,則以左子節點做爲當前節點;若是新增節點等於當前節點,則用新增節點覆蓋當前節點,並結束循環 直到某個節點的左右子節點不存在,將新節點添加爲該節點的子節點。若是新節點比該節點大,則添加其爲右子節點。若是新節點比該節點小,則添加其爲左子節點;