TreeMap

需要先了解紅黑樹,這是之前分析紅黑樹的文章。
之前在分析紅黑樹時,我認為紅黑樹=二叉查找樹+紅黑平衡,關于二叉查找樹這是遞歸版本的,而在TreeMap中實現的是非遞歸版本的。
TreeMap的繼承關系:


關于SortedMap,NavigableMap

get與put操作都很簡單,注意TreeMap不允許鍵為null,對TreeMap來說comparator不為null則利用該比較器進行key鍵比較,否則利用key鍵本身這要求鍵必須實現Comparable接口,實現自己的compareTo邏輯,所以對于TreeMap作為鍵的對象要么你提供一個comparator比較器,要么這個對象是Comparable。
對于HashMap,它允許一個鍵為null的節點,因為HashMap比較的是hash值(null的hash值在HashMap中為0),但作為鍵的對象最好重寫equals方法,當然重寫equals就應該重寫hashcode方法。
1.8后Comparator接口更加強健,配合lambda,代碼更加簡潔易懂。

remove

    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }

    private void deleteEntry(Entry<K,V> p) {
        modCount++;
        size--;

        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        if (p.left != null && p.right != null) {
            Entry<K,V> s = successor(p);
            p.key = s.key;
            p.value = s.value;
            p = s;
        } // p has 2 children

        // Start fixup at replacement node, if it exists.
        Entry<K,V> replacement = (p.left != null ? p.left : p.right);

        if (replacement != null) {
            // Link replacement to parent
            replacement.parent = p.parent;
            if (p.parent == null)
                root = replacement;
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;

            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null;

            // Fix replacement
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
        } else if (p.parent == null) { // return if we are the only node.
            root = null;
        } else { //  No children. Use self as phantom replacement and unlink.
            if (p.color == BLACK)
                fixAfterDeletion(p);

            if (p.parent != null) {
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }

若當前節點的左右皆不為空,則找到其右子節點的最左節點與其進行鍵值的替換,問題就轉化為刪除這個最小節點。所以最后要刪除的節點存在兩種情況:1,沒有子節點。2,只有一個子孩子非空。對于這兩種情況的處理不同。情況1,若它顏色為黑則先進行紅黑調整fixAfterDeletion,后在根據情況進行刪除。該方法介紹在紅黑樹。情況2,先刪除該節點,若其為黑,對其左/右子樹進行紅黑平衡。

successor

    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;
        }
    }

返回的是最接近的大于t的節點,就是大于t的節點中最小的那個節點。
兩種情況,右子孩子非空則返回其最左節點;為空則沿著右連接往上直到拐點。


圖中t, E是父子關系。
按照上面的代碼返回的就是的就是P節點,對于P若它有右子樹那么也只可能有一個節點,且為紅,這是由紅黑樹性質決定的。P是大于t節點中是最接近于t的,你可以在該圖中任意延申擴展,在根據大小關系推,便可得到證明。

圖中P,M是父子關系。
P節點是大于 t 中最小的節點,也就是最接近的節點。

predecessor(t)
該方法返回的是小于 t 的節點中最大的節點,也就是最接近的節點。

    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;
        }
    }

像上面一樣畫出圖就能夠看出。

之前在SortedMap,NavigableMap中介紹了很多返回各種視圖的方法,現在來看看在TreeMap中的實現。

lowerEntry

返回最接近的小于key的Entry

    public Map.Entry<K,V> lowerEntry(K key) {
        return exportEntry(getLowerEntry(key));
    }

    static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
        return (e == null) ? null :
            new AbstractMap.SimpleImmutableEntry<>(e);
    }

    final Entry<K,V> getLowerEntry(K key) {
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = compare(key, p.key);
            if (cmp > 0) {
                if (p.right != null)
                    p = p.right;
                else
                    return p;
            } else {
                if (p.left != null) {
                    p = p.left;
                } else {
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.left) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    return parent;
                }
            }
        }
        return null;
    }

1,getLowerEntry


下面所說的左鏈路:上面的節點一定大于key。右鏈路:上面的節點一定小于key。所以每條鏈路并不包括末尾的拐點,它是下一條鏈路的開始節點。

圖中代表的是一段尋找的路徑,同中K,P和A,B是父子關系。按照代碼可知A節點就是最接近key的節點,為什么?所有左鏈接上的節點都是大于key的,那么最接近的一定是那個右路徑上最大的節點,A就是,比如A與E比較,
T > E > key;A > T。所以A > E,任意取右鏈路上的節點都可得到此結論,由此可推斷出A是路徑中所有右鏈路中最大的節點,也就是最接近key的節點。

上面證明了路徑中最后一條右鏈路的末尾節點(不是指拐點,如B,它是左鏈路開頭節點)一定是最接近key的節點。但是,還有一個疑問,除了這條鏈路的其它樹節點就一定不符合嗎?是的,它們一定不符合,從上往下的尋找中往左拐說明該拐點大于key,向左尋找小于key的節點,找到后向右拐說明該拐點小于key,向其右側尋找介于該拐點與key之間最大的值,如上圖中K與P節點,K < key,此時K的左兒子P,P < K所以P一定不是最接近的。所以要找到null為止,再根據null是左兒子或右兒子的情況來做相應處理,處理就是找到最后的右鏈路的最后節點。
所以當p.right == null 時,p就是那個最接近的節點,直接返回。

2,exportEntry

    static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
        return (e == null) ? null :
            new AbstractMap.SimpleImmutableEntry<>(e);
    }

getLowerEntry返回那個最接近key的節點,獲取其key與value構造一個SimpleImmutableEntry對象,然后返回。SimpleImmutableEntry提供一些基本方法如getKey,getValue,equals,hashcode,toString,它的setValue拋出UnsupportedOperationException異常,也就是不可改變

其它方法如:lowerKey,floorEntry,floorKey代碼邏輯與lowerEntry相同。
higherEntry,higherKey,ceilingEntry,ceilingKey處理方法與lowerEntry相反,它們找的是路徑中最后的左鏈路的最后節點。

下面來分析一個內部類NavigableSubMap,它與之后要分析的很多方法有關。

NavigableSubMap

只對原TreeMap的一部分即子map進行操作,對這部分的可以put,get,remove,ceilingEntry,higherKey....就像一個新的TreeMap,但并非如此,你的操作被限定在一定范圍內,并且是直接影響到原map的,本質上就是在對原map樹的相應節點進行操作,這就是NavigableSubMap實現的功能,也就是塑造一個特定范圍的原map的視圖,仍然是同一map,操作互相影響。
所以你在下面的代碼會看到NavigableSubMap里的put,get,remove.....等方法底層都是調用TreeMap的相應方法來實現,只不過在開始加了范圍的判斷。

    abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
        implements NavigableMap<K,V>, java.io.Serializable {
        private static final long serialVersionUID = -2102997345730753016L;

        final TreeMap<K,V> m;

通過這6個變量來控制起始與結束邊界。
(fromStart,lo,loInclusive)代表起點,若fromStart為true則為map的最左節點,即最小。
若fromStart為false,lo為起點,是否包含lo由loInclusive決定。
(toEnd, hi, hiInclusive)代表終點,規則與上面一樣。
        final K lo, hi;
        final boolean fromStart, toEnd;
        final boolean loInclusive, hiInclusive;

        NavigableSubMap(TreeMap<K,V> m,
                        boolean fromStart, K lo, boolean loInclusive,
                        boolean toEnd,     K hi, boolean hiInclusive) {
...................
        }

一些判斷邊界的方法:tooLow,tooHigh,inRange(Object key),inClosedRange,inRange(Object key, boolean inclusive),代碼就不貼了。
另一類方法,如absLowest,返回范圍內最小節點

        final TreeMap.Entry<K,V> absLowest() {
            TreeMap.Entry<K,V> e =
                (fromStart ?  m.getFirstEntry() :
                 (loInclusive ? m.getCeilingEntry(lo) :
                                m.getHigherEntry(lo)));
            return (e == null || tooHigh(e.key)) ? null : e;
        }

方法邏輯很清晰,利用的方法的邏輯在上面解析過。
類似的方法還有:
absHighest范圍內最大節點。
absCeiling(K key)范圍內最接近的大于等于key的節點,為null說明超過上界。
absHigher(K key)范圍內最接近的大于key的節點。
absFloor(K key)范圍內最接近的小于等于key的節點
absLower(K key)范圍內最接近的小于key的節點
absHighFence返回最接近的大于范圍內最大值的節點
absLowFence返回最接近的小于范圍內最小值的節點

還有一些讓子類去實現發抽象方法

        abstract TreeMap.Entry<K,V> subLowest();
        abstract TreeMap.Entry<K,V> subHighest();
        abstract TreeMap.Entry<K,V> subCeiling(K key);
        abstract TreeMap.Entry<K,V> subHigher(K key);
        abstract TreeMap.Entry<K,V> subFloor(K key);
        abstract TreeMap.Entry<K,V> subLower(K key);

升序
        abstract Iterator<K> keyIterator();

        abstract Spliterator<K> keySpliterator();

降序
        abstract Iterator<K> descendingKeyIterator();

接下來是由NavigableSubMap重新實現的操作方法

NavigableSubMap是個abstract類,AbstractMap的entrySet方法它并沒有實現,
而是交給了子類去實現
        public boolean isEmpty() {
            return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
        }

        public int size() {
            return (fromStart && toEnd) ? m.size() : entrySet().size();
        }

        public final boolean containsKey(Object key) {
            return inRange(key) && m.containsKey(key);
        }

        public final V put(K key, V value) {
            if (!inRange(key))
                throw new IllegalArgumentException("key out of range");
            return m.put(key, value);
        }

        public final V get(Object key) {
            return !inRange(key) ? null :  m.get(key);
        }

        public final V remove(Object key) {
            return !inRange(key) ? null : m.remove(key);
        }

剩下的這些方法調用的各種subxxx()方法,都是要由子類去實現的
        public final Map.Entry<K,V> ceilingEntry(K key) {
            return exportEntry(subCeiling(key));
        }

        public final K ceilingKey(K key) {
            return keyOrNull(subCeiling(key));
        }

        public final Map.Entry<K,V> higherEntry(K key) {
            return exportEntry(subHigher(key));
        }

        public final K higherKey(K key) {
            return keyOrNull(subHigher(key));
        }

        public final Map.Entry<K,V> floorEntry(K key) {
            return exportEntry(subFloor(key));
        }

        public final K floorKey(K key) {
            return keyOrNull(subFloor(key));
        }

        public final Map.Entry<K,V> lowerEntry(K key) {
            return exportEntry(subLower(key));
        }

        public final K lowerKey(K key) {
            return keyOrNull(subLower(key));
        }

        public final K firstKey() {
            return key(subLowest());
        }

        public final K lastKey() {
            return key(subHighest());
        }

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

        public final Map.Entry<K,V> lastEntry() {
            return exportEntry(subHighest());
        }

        public final Map.Entry<K,V> pollFirstEntry() {
            TreeMap.Entry<K,V> e = subLowest();
            Map.Entry<K,V> result = exportEntry(e);
            if (e != null)
                m.deleteEntry(e);
            return result;
        }

        public final Map.Entry<K,V> pollLastEntry() {
            TreeMap.Entry<K,V> e = subHighest();
            Map.Entry<K,V> result = exportEntry(e);
            if (e != null)
                m.deleteEntry(e);
            return result;
        }

接下來介紹各種視圖方法,

        降序視圖
        transient NavigableMap<K,V> descendingMapView;
        Entry視圖
        transient EntrySetView entrySetView;
        key視圖
        transient KeySet<K> navigableKeySetView;

        public final NavigableSet<K> navigableKeySet() {
            KeySet<K> nksv = navigableKeySetView;
            return (nksv != null) ? nksv :
                (navigableKeySetView = new TreeMap.KeySet<>(this));
        }

        public final Set<K> keySet() {
            return navigableKeySet();
        }

這里descendingMap()是NavigableMap接口的方法,NavigableSubMap并沒有實現它,
交由子類去實現
        public NavigableSet<K> descendingKeySet() {
            return descendingMap().navigableKeySet();
        }
subMap()同上,實現在子類
        public final SortedMap<K,V> subMap(K fromKey, K toKey) {
            return subMap(fromKey, true, toKey, false);
        }
headMap同上,實現在子類
        public final SortedMap<K,V> headMap(K toKey) {
            return headMap(toKey, false);
        }
tailMap同上,實現在子類
        public final SortedMap<K,V> tailMap(K fromKey) {
            return tailMap(fromKey, true);
        }

來看看各個視圖的類
EntrySetView

        abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
            private transient int size = -1, sizeModCount;

            public int size() {
                if (fromStart && toEnd)
                    return m.size();
                if (size == -1 || sizeModCount != m.modCount) {
                    sizeModCount = m.modCount;
                    size = 0;
                    Iterator<?> i = iterator();
                    while (i.hasNext()) {
                        size++;
                        i.next();
                    }
                }
                return size;
            }

            public boolean isEmpty() {
                TreeMap.Entry<K,V> n = absLowest();
                return n == null || tooHigh(n.key);
            }

            public boolean contains(Object o) {
                if (!(o instanceof Map.Entry))
                    return false;
                Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
                Object key = entry.getKey();
                if (!inRange(key))
                    return false;
                TreeMap.Entry<?,?> node = m.getEntry(key);
                return node != null &&
                    valEquals(node.getValue(), entry.getValue());
            }

            public boolean remove(Object o) {
                if (!(o instanceof Map.Entry))
                    return false;
                Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
                Object key = entry.getKey();
                if (!inRange(key))
                    return false;
                TreeMap.Entry<K,V> node = m.getEntry(key);
                if (node!=null && valEquals(node.getValue(),
                                            entry.getValue())) {
                    m.deleteEntry(node);
                    return true;
                }
                return false;
            }
        }

迭代器SubMapIterator

        abstract class SubMapIterator<T> implements Iterator<T> {
            TreeMap.Entry<K,V> lastReturned; 用于記錄本次返回的接待你
            TreeMap.Entry<K,V> next; 指向下次要返回的節點
在向前或向后遍歷時需要知道上下邊界在哪,達到該邊界就代表超出范圍
            final Object fenceKey;  
            int expectedModCount;

            SubMapIterator(TreeMap.Entry<K,V> first,
                           TreeMap.Entry<K,V> fence) {
                expectedModCount = m.modCount;
                lastReturned = null;
                next = first;
                fenceKey = fence == null ? UNBOUNDED : fence.key;
            }

            public final boolean hasNext() {
                return next != null && next.key != fenceKey;
            }

上面說過successor返回的是大于e節點中的最小的那個節點,所以順序性得到保證。
            final TreeMap.Entry<K,V> nextEntry() {
                TreeMap.Entry<K,V> e = next;
                if (e == null || e.key == fenceKey)
                    throw new NoSuchElementException();
                if (m.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                next = successor(e);
                lastReturned = e;
                return e;
            }

predecessor返回的是小于e節點中的最大的那個節點,遍歷得到的結果是從大到小的順序。
            final TreeMap.Entry<K,V> prevEntry() {
                TreeMap.Entry<K,V> e = next;
                if (e == null || e.key == fenceKey)
                    throw new NoSuchElementException();
                if (m.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                next = predecessor(e);
                lastReturned = e;
                return e;
            }

該方法是與nextEntry配合的,不能和preEntry混用
            final void removeAscending() {
                if (lastReturned == null)
                    throw new IllegalStateException();
                if (m.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
在遍歷過程中得到了一個節點e,現在要刪除它,此時lastReturned同樣指向e,
若其左右子樹皆不為null,則在deleteEntry刪除過程中實際刪除的是successor返回的節點,
而它正是next指針在此時指向的節點,所以需要下面這步。
                if (lastReturned.left != null && lastReturned.right != null)
                    next = lastReturned;
                m.deleteEntry(lastReturned);
                lastReturned = null;
                expectedModCount = m.modCount;
            }

該方法是與preEntry配合使用
            final void removeDescending() {
                if (lastReturned == null)
                    throw new IllegalStateException();
                if (m.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                m.deleteEntry(lastReturned);
                lastReturned = null;
                expectedModCount = m.modCount;
            }

        }

各種繼承SubMapIterator實現的不同迭代器

Entry的升序迭代器
        final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
            SubMapEntryIterator(TreeMap.Entry<K,V> first,
                                TreeMap.Entry<K,V> fence) {
                super(first, fence);
            }
            public Map.Entry<K,V> next() {
                return nextEntry();
            }
            public void remove() {
                removeAscending();
            }
        }

Entry的降序迭代器
        final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
            DescendingSubMapEntryIterator(TreeMap.Entry<K,V> last,
                                          TreeMap.Entry<K,V> fence) {
                super(last, fence);
            }

            public Map.Entry<K,V> next() {
                return prevEntry();
            }
            public void remove() {
                removeDescending();
            }
        }

鍵的升序迭代器
        final class SubMapKeyIterator extends SubMapIterator<K>
            implements Spliterator<K> {
            SubMapKeyIterator(TreeMap.Entry<K,V> first,
                              TreeMap.Entry<K,V> fence) {
...............
        }

鍵的降序迭代器
        final class DescendingSubMapKeyIterator extends SubMapIterator<K>
            implements Spliterator<K> {
            DescendingSubMapKeyIterator(TreeMap.Entry<K,V> last,
                                        TreeMap.Entry<K,V> fence) {
.....................
        }

接下來看看NavigableSubMap的用途:


subMap

【fromKey, toKey)左閉右開,返回該區間范圍內的原map的視圖
    public SortedMap<K,V> subMap(K fromKey, K toKey) {
        return subMap(fromKey, true, toKey, false);
    }

    public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                                    K toKey,   boolean toInclusive) {
        return new AscendingSubMap<>(this,
                                     false, fromKey, fromInclusive,
                                     false, toKey,   toInclusive);
    }

AscendingSubMap

    static final class AscendingSubMap<K,V> extends NavigableSubMap<K,V> {
        private static final long serialVersionUID = 912986545866124060L;

        AscendingSubMap(TreeMap<K,V> m,
                        boolean fromStart, K lo, boolean loInclusive,
                        boolean toEnd,     K hi, boolean hiInclusive) {
            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
        }

        public Comparator<? super K> comparator() {
            return m.comparator();
        }

        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                                        K toKey,   boolean toInclusive) {
            if (!inRange(fromKey, fromInclusive))
                throw new IllegalArgumentException("fromKey out of range");
            if (!inRange(toKey, toInclusive))
                throw new IllegalArgumentException("toKey out of range");
            return new AscendingSubMap<>(m,
                                         false, fromKey, fromInclusive,
                                         false, toKey,   toInclusive);
        }

        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
            if (!inRange(toKey, inclusive))
                throw new IllegalArgumentException("toKey out of range");
            return new AscendingSubMap<>(m,
                                         fromStart, lo,    loInclusive,
                                         false,     toKey, inclusive);
        }

        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
            if (!inRange(fromKey, inclusive))
                throw new IllegalArgumentException("fromKey out of range");
            return new AscendingSubMap<>(m,
                                         false, fromKey, inclusive,
                                         toEnd, hi,      hiInclusive);
        }

        public NavigableMap<K,V> descendingMap() {
            NavigableMap<K,V> mv = descendingMapView;
            return (mv != null) ? mv :
                (descendingMapView =
                 new DescendingSubMap<>(m,
                                        fromStart, lo, loInclusive,
                                        toEnd,     hi, hiInclusive));
        }

        Iterator<K> keyIterator() {
            return new SubMapKeyIterator(absLowest(), absHighFence());
        }

        Spliterator<K> keySpliterator() {
            return new SubMapKeyIterator(absLowest(), absHighFence());
        }

        Iterator<K> descendingKeyIterator() {
            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
        }

        final class AscendingEntrySetView extends EntrySetView {
            public Iterator<Map.Entry<K,V>> iterator() {
                return new SubMapEntryIterator(absLowest(), absHighFence());
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            EntrySetView es = entrySetView;
            return (es != null) ? es : (entrySetView = new AscendingEntrySetView());
        }

        TreeMap.Entry<K,V> subLowest()       { return absLowest(); }
        TreeMap.Entry<K,V> subHighest()      { return absHighest(); }
        TreeMap.Entry<K,V> subCeiling(K key) { return absCeiling(key); }
        TreeMap.Entry<K,V> subHigher(K key)  { return absHigher(key); }
        TreeMap.Entry<K,V> subFloor(K key)   { return absFloor(key); }
        TreeMap.Entry<K,V> subLower(K key)   { return absLower(key); }
    }

代碼設計時要低耦合高復用,NavigableSubMap就充分實現了這一準則。比如當你調用subMap得到了一個SortedMap對象,調用isEmpty()方法,Debug看看這一過程,它在多個方法與內部類中跳轉。

類似用AscendingSubMap來實現視圖的方法有:

大于fromKey的視圖,inclusive控制是否包括fromKey
    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
        return new AscendingSubMap<>(this,
                                     false, fromKey, inclusive,
                                     true,  null,    true);
    }

小于toKey的視圖
    public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
        return new AscendingSubMap<>(this,
                                     true,  null,  true,
                                     false, toKey, inclusive);
    }

descendingMap()

    public NavigableMap<K, V> descendingMap() {
        NavigableMap<K, V> km = descendingMap;
        return (km != null) ? km :
            (descendingMap = new DescendingSubMap<>(this,
                                                    true, null, true,
                                                    true, null, true));
    }

DescendingSubMap
AscendingSubMap是升序的子map視圖,而DescendingSubMap與其相反,它是從上邊界往下邊界的順序,這就是二者的不同,除此之外它們的實現思路相同。

TreeMap還有很多的內部類,即相關操作,之后再分析.........

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容