[Java] TreeMap - 源代碼學習筆記


TreeMap 實現了 SortedMap 和 NavigableMap 接口,所有本文還會記錄 SortedMap 和 NavigableMap 的閱讀筆記。

SortedMap

1. 排序的比較應該和 equals(Object) 保持一致

2. 應該提供四種“標准”的構造器

  1). 無參構造器

  2). 帶一個 Comparator 為參數的構造器

  3). 帶一個 Map 為參數的構造器

  4). 帶一個 SortedMap 為參數的構造器

3.  subMap ,  headMap ,  tailMap ,  KeySet values entrySet  等方法返回的 Map 或 Set 和 SortedMap 本身使用同一份數據,所以對 subMap 返回的 Map 進行修改,同樣會反映到 SortedMap 上。

 

NavigableMap

1. lowerEntry, floorEntry, ceilingEntry, higherEntry 分別返回 小於、小於或等於,大於或等於,以及大於給定 key 的 Map.Entry。這類型的方法用於定位離目標給定值最近的元素。

2. 增長序 map 的操作比遞減序的 map 的操作要快。

3. 返回 entry 的方法返回的是那一刻的 entry 快照,所以通常不支持 Entry.setValue 方法。

例如, TreeMap 實現 NavigableMap 的 firstEntry,返回會的就是根據給定 entry 的 key, value 新建的不可變 

SimpleImmutableEntry 對象。

4. pollFirstEntry 刪除並返回第一個元素

 

TreeMap

1. 基於紅黑樹的實現

2. 根據自然序,或者給定的比較器是內部元素保持有序。

3. 提供復雜度為 log(n) 的 containsKey, get, put, remove 操作

4. itertator 采用 fast-fail 機制

5. values 繼承於 Collection, EntrySet 和 KeySet 則繼承於 Set

6. DeletionEntry 刪除指定的元素,fixAfterDeletion 對刪除后的樹節點進行再平衡,使得 TreeMap 保持紅黑樹的特性。

7. containsValue(Object) 通過遍歷所有元素,來判斷是否包含指定的值為 value。因此,效率低。

    public boolean containsValue(Object value) {
        for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
            if (valEquals(value, e.value))
                return true;
        return false;
    }

8. getFirstEntry 返回樹中最左下角的元素

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

getLastEntry 返回樹中最右下角的元素

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

  

9. successor(Entry e) 

當 e 為 null 時,返回 null

當 e 有右子節點時,則返回右子節點的最左下角后代節點

當 e 沒有右子節點時,返回一個離 e 最近的祖先節點,該祖先節的左孩子也是 e 的祖先節點。

    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            return null;
        else if (t.right != null) {
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        } else {
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

10. prodecessor(Entry e) 和 successor(Entry e) 思路相似。

當 e 為 null 時,返回 null

當 e 有左子節點時,則返回左子節點的最右下角后代節點

當 e 沒有左子節點時,返回一個離 e 最近的祖先節點,該祖先節的右孩子也是 e 的祖先節點。

    static <K,V> Entry<K,V> predecessor(Entry<K,V> t) {
        if (t == null)
            return null;
        else if (t.left != null) {
            Entry<K,V> p = t.left;
            while (p.right != null)
                p = p.right;
            return p;
        } else {
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.left) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

11. get(Object):VgetEntry(Object):Entry 的不同點在於,前者返回 V, 而后者返回 Entry。獲取的算法一樣,因為 get 是基於 getEntry 來實現的。

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

12. containsKey(Object) 同樣也是基於 getEntry 來實現的

    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

13. computeRedLevel(int) ,應用於復制一個 map 到當前為空的 TreeMap 的操作中。復制后的 TreeMap 應該是一棵完全二叉樹(complete binary tree),通過將其中滿足完美二叉樹(perfect binary tree)部分的節點塗黑,則可以簡單地實現紅黑樹的黑屬性

    private static int computeRedLevel(int sz) {
        int level = 0;
        for (int m = sz - 1; m >= 0; m = m / 2 - 1)
            level++;
        return level;
    }

下面是一個完全二叉樹的例子,其中滿足完美二叉樹的只有 0 - 7 個節點,也就是 0 - 2 層。0 - 2 層的節點全部塗黑色,最后一層則全部塗紅色。則最方便地滿足紅黑樹的特性。

14. buildFromSorted, 采用遞歸的思路,先構建后節點的左子樹,在構建好節點的右子樹,最后和節點組合成一個完整的子樹。

15. putAll(Map)

當 TreeMap 沒有元素,Map 是一個 sortMap, 並且 Map 的比較器等於 TreeMap 的比較器,則采用 buildFormSorted 來構建 TreeMap。

否則,將 Map 中每個 mapping,通過調用 put(K, V) 來插入 TreeMap 中。

    public void putAll(Map<? extends K, ? extends V> map) {
        int mapSize = map.size();
        if (size==0 && mapSize!=0 && map instanceof SortedMap) {
            Comparator<?> c = ((SortedMap<?,?>)map).comparator();
            if (c == comparator || (c != null && c.equals(comparator))) {
                ++modCount;
                try {
                    buildFromSorted(mapSize, map.entrySet().iterator(),
                                    null, null);
                } catch (java.io.IOException cannotHappen) {
                } catch (ClassNotFoundException cannotHappen) {
                }
                return;
            }
        }
        super.putAll(map);
    }

16. getEntry, getEntryUsingComparator, getCeilingEntry, getFloorEntry, getHigherEntry, getLowerEntry 都是基於二分查找思路來實現元素操作。

17. put(K, V)

當已存在 key 和 K 相等的 Entry, 則直接更新這個 Entry 的 value 值。

否則,插入新的 Entry ,然后自平衡樹結構。

18. remove(Object),刪除指定節點,然后自平衡樹結構

19. clear(), 將 root 至 null 即可

    public void clear() {
        modCount++;
        size = 0;
        root = null;
    }

20.  firstEntry 返回不可變的 Entry , getFirstEntry 則返回可變的 Entry。同樣關系的還有:lastEntrygetLastEntrylowerEntrygetLowerEntry, higherEntrygetHigherEntry

  

 

Jdk 版本: jdk1.8.0_31.jdk

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM