jdk原始碼分析之TreeMap

weixin_34236869發表於2018-06-26

1.TreeMap簡介

TreeMap是通過紅黑樹來實現一個有序的key-value集合的。
TreeMap是基於紅黑樹實現的,該對映可以根據他的鍵的自然順序進行排序,也可以根據為建構函式提供的比較器進行排序。
TreeMap的基本操作containsKey,get,put,remove的時間複雜度是log(n),另外TreeMap是非同步的。

2.TreeMap資料結構

TreeMap的繼承關係

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable {}

1.由繼承關係可知,TreeMap繼承與AbstractMap,並且實現了Navigable介面。
2.TreeMap的本質是紅黑樹,它包含幾個重要的成員變數,root,size,comparator。其中root是紅黑樹的節點,他的型別是Entry,它包含key,value,left(左孩子),right(右孩子),parent(父節點),color(顏色)。Entry節點根據key進行排序;可以是自然排序,也可以根據比較器來進行排序;size是紅黑樹節點中的個數。

3.TreeMap原始碼分析

3.1紅黑樹相關

//紅黑樹的節點顏色--紅色
private static final boolean RED = false;
//紅黑樹的節點顏色--黑色
private static final boolean BLACK = true;

//紅黑樹左旋
private void rotateLeft(Entry<K,V> p) { ... }
//紅黑樹右旋
private void rotateRight(Entry<K,V> p) { ... }
//紅黑樹插入操作
public V put(K key, V value) { ... }
//紅黑樹插入修正操作,保證在進行插入之後,任然是一顆紅黑樹
private void fixAfterInsertion(Entry<K,V> x) { ... }
//紅黑色的刪除操作
private void deleteEntry(Entry<K,V> p) { ... }
//紅黑樹刪除修正操作,保證在進行刪除之後,任然是一顆紅黑樹
private void fixAfterDeletion(Entry<K,V> x) { ... }

3.2TreeMap的建構函式

1.預設建構函式

public TreeMap() {
    comparator = null;
}

2.帶比較器的建構函式

public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}

3.有Map的建構函式

public TreeMap(Map<? extends K, ? extends V> m) {
    comparator = null;
    putAll(m);
}

其中putAll()會把m中的所有元素新增到TreeMap中,其中putAll的原始碼如下:

public void putAll(Map<? extends K, ? extends V> m) {
    for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
        put(e.getKey(), e.getValue());
}

3.3TreeMap中與Entry相關的函式

與Entry相關的函式

//以下與Entry相關的函式原理大同小異
firstEntry()
lastEntry()
lowerEntry()
higherEntry()
floorEntry()
ceilingEntry()
pollFirstEntry()
pollLastEntry()

再次以firstEntry()為例子進行說明:

public Map.Entry<K,V> firstEntry() {
    return exportEntry(getFirstEntry());
}

final Entry<K,V> getFirstEntry() {
    Entry<K,V> p = root;
    if (p != null)
        while (p.left != null)
            p = p.left;
    return p;
}

firstEntry()和getFirstEntry()都是用於獲取第一個節點。firstEntry()是對外介面,getFirstEntry()是對內介面。為什麼外界不直接呼叫getFirstEntry()來實現,而是通過呼叫firstEntry()來獲取第一個Entry呢?這樣做的目的是為了防止使用者修改返回的Entry.

3.4TreeMap中與Key相關的函式

//以下與key有關的函式原理類似
firstKey()
lastKey()
lowerKey()
higherKey()
floorKey()
ceilingKey()
//該函式返回大於/等於key的最小的鍵值對所對應的key,沒有的話就返回null
public K ceilingKey(K key) {
    return keyOrNull(getCeilingEntry(key));
}

static <K,V> K keyOrNull(TreeMap.Entry<K,V> e) {
    return e == null? null : e.key;
}

相關文章