Map
在 Java Collections Framework 中設計相關知識點比較多的數據結構,不管是工做仍是面試中都會被頻繁的涉及到。經過學習 Map
的源碼,咱們可以深刻理解至關部分的數據結構知識和編碼技巧。在接下來的幾篇文章中會介紹一些數據結構的知識,但願你們不會以爲無聊,由於這部分的能力纔是做爲程序員的核心能力。同時這部分的知識其實也不是那麼高深,我會試着用最簡單明瞭的方法幫你理解。node
Map
數據結構的特色很明顯,容許咱們使用 key 來存儲和讀取元素,而且不容許重複的 key。而不一樣 Map
的實現對於 key 的順序處理是不一致的。例如 HashMap
沒法保證 key 的順序,而 TreeMap
則是按照 key 實現的 Comparator
接口方法來肯定順序的。程序員
Map
上也定義了每個 key-value 對應的數據必須實現 Entry
接口,上面定義的方法也很簡單,基本都是對於 key 和 value 的操做。面試
Map
接口上定義的方法,你們應該都比較熟悉,我這裏就不囉嗦了。特別會說起在 JDK8 加入的幾個方法,在平常工做中比較實用。若是以前沒有 JDK8 使用經驗的,能夠了解一下。算法
* `getOrDefalut(Object key, V defaultValue)`:當 `Map` 中有 key 對應的 value 時返回 `Map` 中的 value, 不然返回 `defaultValue` 。 * `V compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction)`:將 `Map` 中的 key 和對應的 value 做爲參數,調用 `remappingFunction` 方法得到 newValue,若是 newValue 不爲 null,則替換原來的 value。 * `V putIfAbsent(K key, V value)`:若是當前 `Map` 中沒有 key 對應的 value,則執行 put 操做。 * `V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)`:若是當前沒有 key 對應的 value,則將參數 value 放入 `Map` 中,不然將原來 key 對應的 value 和新的 value 做爲參數調用 `remappingFunction` ,將結果 put 入 `Map` 中。
這些方法的實現都在 Map
接口中,使用的 JDK8 新增的 default
關鍵字以保持向下兼容,具體的代碼很是簡單,這裏就不囉嗦了。安全
相對 HashMap
而言,TreeMap
涉及的知識點更少些,適合做爲熟悉 Map
數據結構的敲門磚。先來看看它的類圖:微信
能夠看到 TreeMap
繼承了 AbstractMap
,並實現了 NavigableMap
接口。AbstractMap
上提供了部分模版方法,便於開發人員實現本身的 Map
,而 NavigableMap
提供了相似以前說起的 NavigableSet
的那些方法,可以返回某個範圍的 key 或是 value。因此咱們直接來看 TreeMap
的具體實現細節。數據結構
從一開頭的註釋中能夠得知,TreeMap
是經過紅黑樹這一數據結構實現的,所以它可以保證 containsKey
,get
,put
,remove
的時間複雜度爲 log(n)
。而一樣的,TreeMap
也不是線程安全的。因此真正理解 TreeMap
的關鍵在於瞭解和掌握紅黑樹的這一數據結構。因此接下來的部分,我先會花些篇幅幫助你複習一下紅黑樹的特性,不要以爲這是個很難任務,我保證你看完系列文章後必定可以用 Java 手寫紅黑樹。app
用一句話來講紅黑樹是一種平衡二叉樹。二叉樹的概念你們應該都知道,即每一個父節點擁有不超過兩個子節點的樹。而平衡的意思是左右子樹的高度相差不超過一。同時全部左邊子樹的值都比當前節點小,而右邊子樹的值都比當前節點大。咱們來看一下幾個例子。源碼分析
能夠看到圖1是一棵平衡二叉樹,符合咱們以前提到的條件,可是圖2就不符合了,由於左右子樹的高度相差超過了一。學習
維持平衡的目的在於不讓二叉樹退化爲鏈表,這樣就能夠進行二分查找,保持查找的時間複雜度爲 log(n)
。但這也意味着在增長節點或是移除節點的時候須要作特殊的操做,以保持整個二叉樹的平衡,而紅黑樹就是這樣的一種數據結構。
像以前說起的,紅黑樹自己是一種平衡二叉樹,所以它具有平衡二叉樹的全部特色。在此基礎上它有一些本身特有的約束條件與特性。
紅黑樹的每一個節點額外增長了一個顏色的特性,即紅色,或是黑色,只能是這兩個中的一種,這也是它紅黑樹名稱的由來。咱們看一下 TreeMap
中紅黑樹節點的源碼:
static final class Entry<K,V> implements Map.Entry<K,V> { K key; V value; Entry<K,V> left; Entry<K,V> right; Entry<K,V> parent; boolean color = BLACK; }
TreeMap
中每一個節點實現了 Map
中的 Entry 接口,除了表明當前節點的 key,value 兩個數據項,還有代碼自身節點下的左右子節點的 left
和 right
,以及本身父節點的 parent
。最後就是表明當前節點顏色的 color
,這裏的定義一樣在 TreeMap
的源碼中:
private static final boolean RED = false; private static final boolean BLACK = true;
接着咱們看一下紅黑樹的特性:
* 根節點(root node) 的顏色始終爲黑色 * 兩個相鄰的節點(即鏈接在一塊兒的節點)不能同爲紅色 * 從根節點出發,到某個子節點的每條路徑上的黑色節點數量都相同
怎麼樣?夠簡單吧!接着讓咱們看個例子。
從上面的圖來看符合咱們以前列出的 3 個特性,請驗證一下確保本身對紅黑樹的概念理解正確。
經過上面的描述你應該已經掌握了紅黑樹的概念,知道什麼是紅黑樹了。在介紹紅黑樹的插入以及刪除操做以前,咱們先學習三個基本的操做,即顏色變化(color flip),左旋轉(left rotation) 和 右旋轉(right rotation)。
很是簡單,將當前節點顏色變爲紅色,左右兩個子節點的顏色都變爲黑色。入下圖所示。
用語言來描述可能有些抽象,咱們仍是看一下圖片示例,該圖片來自 wikipedia。
請多看幾遍這幅圖,確保本身瞭解左旋轉和右旋轉的意義,由於這三個基本操做是後續紅黑樹插入和刪除操做的基礎。
此次主要介紹了 Map
和 TreeMap
的一些基礎功能,和 TreeMap
之下紅黑樹的基本概念。紅黑樹是一種比較重要的高級數據結構,對於開發人員來講應該是熟練掌握的,本次主要介紹了基本概念和基礎的操做。下一篇咱們會涉及紅黑樹的的插入以及刪除操做的具體算法,在進入這部分前,我再次強調請熟練掌握本文的內容,由於這是基礎中的基礎。
下一篇文章中我會對照 TreeMap
的源碼介紹紅黑樹的算法,但願你不要錯過!
歡迎關注個人微信號「且把金針度與人」,獲取更多高質量文章