内容有序的集合之 TreeMap

HashMap我们了解过了,LinkedHasHMap来实现LRU也介绍过了,有兴趣的可以参阅 Lru实现原理——LinkedHashMap源码解析
现在我们来了解一下TreeMap.

public class TreeMap
    extends AbstractMap
    implements NavigableMap, Cloneable, java.io.Serializable
{
    /**
     * The comparator used to maintain order in this tree map, or
     * null if it uses the natural ordering of its keys.
     *
     * @serial
     */
    private final Comparator comparator;
    
    private transient Entry root;

    /**
     * The number of entries in the tree
     */
    private transient int size = 0;

    /**
     * The number of structural modifications to the tree.
     */
    private transient int modCount = 0;

    public TreeMap() {
        comparator = null;
    }

    public TreeMap(Comparator comparator) {
        this.comparator = comparator;
    }

    public TreeMap(Map m) {
        comparator = null;
        putAll(m);
    }

    public TreeMap(SortedMap m) {
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }

下边我们来查看一下TreeMap的Entry.

static final class Entry implements Map.Entry {
        K key;
        V value;
        Entry left;
        Entry right;
        Entry parent;
        boolean color = BLACK;

        /**
         * Make a new cell with given key, value, and parent, and with
         * {@code null} child links, and BLACK color.
         */
        Entry(K key, V value, Entry parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

        /**
         * Returns the key.
         *
         * @return the key
         */
        public K getKey() {
            return key;
        }

        /**
         * Returns the value associated with the key.
         *
         * @return the value associated with the key
         */
        public V getValue() {
            return value;
        }

        /**
         * Replaces the value currently associated with the key with the given
         * value.
         *
         * @return the value associated with the key before this method was
         *         called
         */
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;

            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
        }

        public int hashCode() {
            int keyHash = (key==null ? 0 : key.hashCode());
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }

        public String toString() {
            return key + "=" + value;
        }
    }

非常明显,Entry是一个二叉树结构。
最重要的是来关注一下TreeMap的put方法,是如何实现有序的。

public V put(K key, V value) {
        Entry t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check
            
            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry parent;
        // split comparator and comparable paths
        Comparator cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
        
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable k = (Comparable) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        
        Entry e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

现在就来看它是如何实现有序的,我们来查看它的遍历方法。

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

    public NavigableSet navigableKeySet() {
        KeySet nks = navigableKeySet;
        return (nks != null) ? nks : (navigableKeySet = new KeySet<>(this));
    }

KeySet内部全部还是调用TreeMap的方法。

 static final class KeySet extends AbstractSet implements NavigableSet {
        private final NavigableMap m;
        KeySet(NavigableMap map) { m = map; }

        public Iterator iterator() {
            if (m instanceof TreeMap)
                return ((TreeMap)m).keyIterator();
            else
                return ((TreeMap.NavigableSubMap)m).keyIterator();
        }

        public Iterator descendingIterator() {
            if (m instanceof TreeMap)
                return ((TreeMap)m).descendingKeyIterator();
            else
                return ((TreeMap.NavigableSubMap)m).descendingKeyIterator();
        }

        public int size() { return m.size(); }
        public boolean isEmpty() { return m.isEmpty(); }
        public boolean contains(Object o) { return m.containsKey(o); }
        public void clear() { m.clear(); }
        public E lower(E e) { return m.lowerKey(e); }
        public E floor(E e) { return m.floorKey(e); }
        public E ceiling(E e) { return m.ceilingKey(e); }
        public E higher(E e) { return m.higherKey(e); }
        public E first() { return m.firstKey(); }
        public E last() { return m.lastKey(); }
        public Comparator comparator() { return m.comparator(); }
        public E pollFirst() {
            Map.Entry e = m.pollFirstEntry();
            return (e == null) ? null : e.getKey();
        }
        public E pollLast() {
            Map.Entry e = m.pollLastEntry();
            return (e == null) ? null : e.getKey();
        }
        public boolean remove(Object o) {
            int oldSize = size();
            m.remove(o);
            return size() != oldSize;
        }
        public NavigableSet subSet(E fromElement, boolean fromInclusive,
                                      E toElement,   boolean toInclusive) {
            return new KeySet<>(m.subMap(fromElement, fromInclusive,
                                          toElement,   toInclusive));
        }
        public NavigableSet headSet(E toElement, boolean inclusive) {
            return new KeySet<>(m.headMap(toElement, inclusive));
        }
        public NavigableSet tailSet(E fromElement, boolean inclusive) {
            return new KeySet<>(m.tailMap(fromElement, inclusive));
        }
        public SortedSet subSet(E fromElement, E toElement) {
            return subSet(fromElement, true, toElement, false);
        }
        public SortedSet headSet(E toElement) {
            return headSet(toElement, false);
        }
        public SortedSet tailSet(E fromElement) {
            return tailSet(fromElement, true);
        }
        public NavigableSet descendingSet() {
            return new KeySet<>(m.descendingMap());
        }

        public Spliterator spliterator() {
            return keySpliteratorFor(m);
        }
    }
Iterator keyIterator() {
        return new KeyIterator(getFirstEntry());
    }
 final class KeyIterator extends PrivateEntryIterator {
        KeyIterator(Entry first) {
            super(first);
        }
        
        public K next() {
            return nextEntry().key;
        }
    }
abstract class PrivateEntryIterator implements Iterator {
        
        Entry next;
        Entry lastReturned;
        int expectedModCount;

        PrivateEntryIterator(Entry first) {
            expectedModCount = modCount;
            lastReturned = null;
            next = first;
        }

        public final boolean hasNext() {
            return next != null;
        }

        final Entry nextEntry() {
            
            Entry e = next;
            if (e == null)
                throw new NoSuchElementException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            
            next = successor(e);
            lastReturned = e;
            return e;
        }
        
        final Entry prevEntry() {
            Entry e = next;
            if (e == null)
                throw new NoSuchElementException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            next = predecessor(e);
            lastReturned = e;
            return e;
        }

        public void remove() {
            if (lastReturned == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            // deleted entries are replaced by their successors
            if (lastReturned.left != null && lastReturned.right != null)
                next = lastReturned;
            deleteEntry(lastReturned);
            expectedModCount = modCount;
            lastReturned = null;
        }
    }

//找到当前节点的下一个节点
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;
        }
    }

predecessor也是类似的,大家可以自行研究,另外entrySet最后也是调用PrivateEntryIterator的nextEntry方法,在这里就不重复分析了。
到此为止,我们明白了,TreeMap顾名思义就是使用Tree来存储数据的,遍历的时候也是通过二叉树的特点来查找下一个节点的,然后保证有序。

你可能感兴趣的:(内容有序的集合之 TreeMap)