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 p = getEntry(key);
        if (p == null)
            return null;

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

    private void deleteEntry(Entry 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 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 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  TreeMap.Entry successor(Entry t) {
        if (t == null)
            return null;
        else if (t.right != null) {
            Entry p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        } else {
            Entry p = t.parent;
            Entry 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  Entry predecessor(Entry t) {
        if (t == null)
            return null;
        else if (t.left != null) {
            Entry p = t.left;
            while (p.right != null)
                p = p.right;
            return p;
        } else {
            Entry p = t.parent;
            Entry ch = t;
            while (p != null && ch == p.left) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

像上面一样画出图就能够看出。

之前在SortedMap,NavigableMap中介绍了很多返回各种视图的方法,现在来看看在TreeMap中的实现。

lowerEntry

返回最接近的小于key的Entry

    public Map.Entry lowerEntry(K key) {
        return exportEntry(getLowerEntry(key));
    }

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

    final Entry getLowerEntry(K key) {
        Entry 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 parent = p.parent;
                    Entry 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  Map.Entry exportEntry(TreeMap.Entry 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 extends AbstractMap
        implements NavigableMap, java.io.Serializable {
        private static final long serialVersionUID = -2102997345730753016L;

        final TreeMap 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 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 absLowest() {
            TreeMap.Entry 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 subLowest();
        abstract TreeMap.Entry subHighest();
        abstract TreeMap.Entry subCeiling(K key);
        abstract TreeMap.Entry subHigher(K key);
        abstract TreeMap.Entry subFloor(K key);
        abstract TreeMap.Entry subLower(K key);

升序
        abstract Iterator keyIterator();

        abstract Spliterator keySpliterator();

降序
        abstract Iterator 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 ceilingEntry(K key) {
            return exportEntry(subCeiling(key));
        }

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

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

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

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

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

        public final Map.Entry 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 firstEntry() {
            return exportEntry(subLowest());
        }

        public final Map.Entry lastEntry() {
            return exportEntry(subHighest());
        }

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

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

接下来介绍各种视图方法,

        降序视图
        transient NavigableMap descendingMapView;
        Entry视图
        transient EntrySetView entrySetView;
        key视图
        transient KeySet navigableKeySetView;

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

        public final Set keySet() {
            return navigableKeySet();
        }

这里descendingMap()是NavigableMap接口的方法,NavigableSubMap并没有实现它,
交由子类去实现
        public NavigableSet descendingKeySet() {
            return descendingMap().navigableKeySet();
        }
subMap()同上,实现在子类
        public final SortedMap subMap(K fromKey, K toKey) {
            return subMap(fromKey, true, toKey, false);
        }
headMap同上,实现在子类
        public final SortedMap headMap(K toKey) {
            return headMap(toKey, false);
        }
tailMap同上,实现在子类
        public final SortedMap tailMap(K fromKey) {
            return tailMap(fromKey, true);
        }

来看看各个视图的类
EntrySetView

        abstract class EntrySetView extends AbstractSet> {
            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 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 node = m.getEntry(key);
                if (node!=null && valEquals(node.getValue(),
                                            entry.getValue())) {
                    m.deleteEntry(node);
                    return true;
                }
                return false;
            }
        }

迭代器SubMapIterator

        abstract class SubMapIterator implements Iterator {
            TreeMap.Entry lastReturned; 用于记录本次返回的接待你
            TreeMap.Entry next; 指向下次要返回的节点
在向前或向后遍历时需要知道上下边界在哪,达到该边界就代表超出范围
            final Object fenceKey;  
            int expectedModCount;

            SubMapIterator(TreeMap.Entry first,
                           TreeMap.Entry 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 nextEntry() {
                TreeMap.Entry 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 prevEntry() {
                TreeMap.Entry 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> {
            SubMapEntryIterator(TreeMap.Entry first,
                                TreeMap.Entry fence) {
                super(first, fence);
            }
            public Map.Entry next() {
                return nextEntry();
            }
            public void remove() {
                removeAscending();
            }
        }

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

            public Map.Entry next() {
                return prevEntry();
            }
            public void remove() {
                removeDescending();
            }
        }

键的升序迭代器
        final class SubMapKeyIterator extends SubMapIterator
            implements Spliterator {
            SubMapKeyIterator(TreeMap.Entry first,
                              TreeMap.Entry fence) {
...............
        }

键的降序迭代器
        final class DescendingSubMapKeyIterator extends SubMapIterator
            implements Spliterator {
            DescendingSubMapKeyIterator(TreeMap.Entry last,
                                        TreeMap.Entry fence) {
.....................
        }

接下来看看NavigableSubMap的用途:


subMap

【fromKey, toKey)左闭右开,返回该区间范围内的原map的视图
    public SortedMap subMap(K fromKey, K toKey) {
        return subMap(fromKey, true, toKey, false);
    }

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

AscendingSubMap

    static final class AscendingSubMap extends NavigableSubMap {
        private static final long serialVersionUID = 912986545866124060L;

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

        public Comparator comparator() {
            return m.comparator();
        }

        public NavigableMap 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 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 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 descendingMap() {
            NavigableMap mv = descendingMapView;
            return (mv != null) ? mv :
                (descendingMapView =
                 new DescendingSubMap<>(m,
                                        fromStart, lo, loInclusive,
                                        toEnd,     hi, hiInclusive));
        }

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

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

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

        final class AscendingEntrySetView extends EntrySetView {
            public Iterator> iterator() {
                return new SubMapEntryIterator(absLowest(), absHighFence());
            }
        }

        public Set> entrySet() {
            EntrySetView es = entrySetView;
            return (es != null) ? es : (entrySetView = new AscendingEntrySetView());
        }

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

代码设计时要低耦合高复用,NavigableSubMap就充分实现了这一准则。比如当你调用subMap得到了一个SortedMap对象,调用isEmpty()方法,Debug看看这一过程,它在多个方法与内部类中跳转。

类似用AscendingSubMap来实现视图的方法有:

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

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

descendingMap()

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

DescendingSubMap
AscendingSubMap是升序的子map视图,而DescendingSubMap与其相反,它是从上边界往下边界的顺序,这就是二者的不同,除此之外它们的实现思路相同。

TreeMap还有很多的内部类,即相关操作,之后再分析.........

你可能感兴趣的:(TreeMap)