Java Collections Framework 源碼分析(5.1 - Map, TreeMap, 紅黑樹)

Java Collections Framework 源碼分析(5.1 - Map, TreeMap, 紅黑樹)

Map 在 Java Collections Framework 中設計相關知識點比較多的數據結構,不管是工做仍是面試中都會被頻繁的涉及到。經過學習 Map 的源碼,咱們可以深刻理解至關部分的數據結構知識和編碼技巧。在接下來的幾篇文章中會介紹一些數據結構的知識,但願你們不會以爲無聊,由於這部分的能力纔是做爲程序員的核心能力。同時這部分的知識其實也不是那麼高深,我會試着用最簡單明瞭的方法幫你理解。node

Map 接口

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 關鍵字以保持向下兼容,具體的代碼很是簡單,這裏就不囉嗦了。安全

TreeMap

相對 HashMap 而言,TreeMap 涉及的知識點更少些,適合做爲熟悉 Map 數據結構的敲門磚。先來看看它的類圖:微信

TreeMap.png

能夠看到 TreeMap 繼承了 AbstractMap ,並實現了 NavigableMap 接口。AbstractMap 上提供了部分模版方法,便於開發人員實現本身的 Map,而 NavigableMap 提供了相似以前說起的 NavigableSet 的那些方法,可以返回某個範圍的 key 或是 value。因此咱們直接來看 TreeMap 的具體實現細節。數據結構

從一開頭的註釋中能夠得知,TreeMap 是經過紅黑樹這一數據結構實現的,所以它可以保證 containsKeygetputremove 的時間複雜度爲 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 兩個數據項,還有代碼自身節點下的左右子節點的 leftright,以及本身父節點的 parent。最後就是表明當前節點顏色的 color,這裏的定義一樣在 TreeMap 的源碼中:

private static final boolean RED   = false;
private static final boolean BLACK = true;

接着咱們看一下紅黑樹的特性:

* 根節點(root node) 的顏色始終爲黑色
* 兩個相鄰的節點(即鏈接在一塊兒的節點)不能同爲紅色
* 從根節點出發,到某個子節點的每條路徑上的黑色節點數量都相同

怎麼樣?夠簡單吧!接着讓咱們看個例子。

rbt.png

從上面的圖來看符合咱們以前列出的 3 個特性,請驗證一下確保本身對紅黑樹的概念理解正確。

紅黑樹的三個基本操做

經過上面的描述你應該已經掌握了紅黑樹的概念,知道什麼是紅黑樹了。在介紹紅黑樹的插入以及刪除操做以前,咱們先學習三個基本的操做,即顏色變化(color flip),左旋轉(left rotation) 和 右旋轉(right rotation)。

顏色變化

很是簡單,將當前節點顏色變爲紅色,左右兩個子節點的顏色都變爲黑色。入下圖所示。

flip.png

左旋轉與右旋轉

用語言來描述可能有些抽象,咱們仍是看一下圖片示例,該圖片來自 wikipedia。

0 (2).png

請多看幾遍這幅圖,確保本身瞭解左旋轉和右旋轉的意義,由於這三個基本操做是後續紅黑樹插入和刪除操做的基礎。

結語

此次主要介紹了 MapTreeMap 的一些基礎功能,和 TreeMap 之下紅黑樹的基本概念。紅黑樹是一種比較重要的高級數據結構,對於開發人員來講應該是熟練掌握的,本次主要介紹了基本概念和基礎的操做。下一篇咱們會涉及紅黑樹的的插入以及刪除操做的具體算法,在進入這部分前,我再次強調請熟練掌握本文的內容,由於這是基礎中的基礎。

下一篇文章中我會對照 TreeMap 的源碼介紹紅黑樹的算法,但願你不要錯過!

歡迎關注個人微信號「且把金針度與人」,獲取更多高質量文章
QR.png

相關文章
相關標籤/搜索