java容器 类TreeMap源码分析

目录

 

简介

字段 comparator,root,size,modCount

Entry类

构造器4个

查询方法 size,containsKey,containsValue,get,comparator,firstKey,lastKey

查询的辅助方法  8个getXXXEntry和getEntryXXX ,successor,predecessor

put方法


简介

/**
 * 一个基于红黑树的NavigableMap实现。
 * 映射根据其键的自然顺序进行排序,或者根据使用的构造函数由创建映射时提供的比较器进行排序。
 * 注意:hashmap支持null的key和value。
 * treemap put时,如果指定key是null,并且map使用自然排序。或者它的comparator不允许null的key,会抛出NullPointerException。
 * treemap允许null的value。
 *
 * 

这个实现为containsKey、get、put和remove操作提供了保证的log(n)时间成本。 * 算法是对Cormen, Leiserson和Rivest介绍的算法的改编。 * *

请注意,如果要正确地实现map接口,树映射(与任何已排序的映射一样)维护的顺序,以及是否提供显式比较器,都必须与equals一致。 * (参见Comparable或Comparator获得与equals一致的精确定义。) * 这是因为Map接口是根据equals操作定义的,但是一个排序后的Map使用它的compareTo(或compare)方法执行所有的键比较, * 所以从排序后的Map的角度来看,这个方法认为相等的两个键是相等的。 * 排序后的映射的行为定义良好,即使它的排序与等于不一致;它只是没有遵守地图接口的通用契约。 * *

注意,这个实现不是同步的。如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步。 * (结构修改是指增加或删除一个或多个映射的操作;仅更改与现有键关联的值不是结构修改)。 * 这通常是通过对一些自然封装了映射的对象进行同步来实现的。 * 如果不存在这样的对象,则应该使用Collections.synchronizedSortedMap方法。 * 这最好在创建时完成,以防止意外的不同步访问地图:

 * 
 *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));
* *

这个类返回的集合视图方法,返回的Iterator是快速失败: * 如果Iterator创建后,map结构上被修改,任何时候以任何方式,除非通过迭代器的删除方法,迭代器将抛出ConcurrentModificationException。 * 因此,在面对并发修改时,迭代器会快速而干净地失败,而不是在将来某个不确定的时间冒任意的、不确定的行为的风险。 * *

注意,不能保证迭代器的快速故障行为,因为通常来说,在存在非同步并发修改的情况下,不可能做出任何严格的保证。 * 故障快速迭代器在最大努力的基础上抛出ConcurrentModificationException。 * 因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速故障行为应该只用于检测bug。 * *

这个类和他的视图,的方法,返回的Map.Entry对,表示它们被生成时的映射快照。 * 他们不支持进入Entry.setValue方法。(但是请注意,可以使用put更改关联映射中的映射。) * * @param the type of keys maintained by this map * @param the type of mapped values * * @author Josh Bloch and Doug Lea * @see Map * @see HashMap * @see Hashtable * @see Comparable * @see Comparator * @see Collection * @since 1.2 */ public class TreeMap extends AbstractMap implements NavigableMap, Cloneable, java.io.Serializable

java容器 类TreeMap源码分析_第1张图片

java容器 类TreeMap源码分析_第2张图片

java容器 类TreeMap源码分析_第3张图片

字段 comparator,root,size,modCount

    /**
     * 比较器用于维护树映射中的顺序,如果使用键的自然顺序,则为null。
     *
     * @serial
     */
    private final Comparator comparator;

    // 红黑树的root
    private transient Entry root;

    /**
     * 树中entry对的数量
     */
    private transient int size = 0;

    /**
     * 对树的结构修改的次数。
     */
    private transient int modCount = 0;

Entry类

    /**
     * 树中的节点。也作为将键-值对传递回用户的工具(参见Map.Entry)。
     */

    static final class Entry implements Map.Entry {
    	// 不是final的key和value
        K key;
        V value;
        // 左孩子,右孩子,父节点
        Entry left;
        Entry right;
        Entry parent;
        // 默认颜色是黑色
        boolean color = BLACK;

        /**
         * 使用给定的键、值和父元素创建一个新节点,并使用空子链接和黑色。
         */
        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;
            // 比较key和value
            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());
            // key的hashcode与value的hashcode异或
            return keyHash ^ valueHash;
        }

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

构造器4个

    /**
     * 使用键的自然顺序构造一个新的空树映射。
     * 插入到映射中的所有键必须实现可比接口。
     * 而且,所有这些键必须是相互可比的:k1. compareto (k2)不能让map中的任何键k1和k2抛出ClassCastException。
     * 如果用户试图将一个键放入违反此约束的映射中
     * (例如,用户试图将一个字符串键放入一个键为整数的映射中),那么put(对象键、对象值)调用将抛出一个ClassCastException。
     */
    public TreeMap() {
        comparator = null;
    }

    /**
     * 构造一个新的空树映射,按照给定的比较器排序。
     * 所有插入到映射中的键必须是可相互比较的,通过给定的比较器:comparator.compare(k1, k2)不能为映射中的任何键k1和k2抛出ClassCastException。
     * 如果用户试图将键放入违反此约束的映射中,则put(对象键、对象值)调用将抛出ClassCastException。
     *
     * @param comparator the comparator that will be used to order this map.
     *        If {@code null}, the {@linkplain Comparable natural
     *        ordering} of the keys will be used.
     */
    public TreeMap(Comparator comparator) {
        this.comparator = comparator;
    }

    /**
     * 构造一个新的树映射,其中包含与给定映射相同的映射,按照键的自然顺序排序。
     * 插入到新映射中的所有键必须实现Comparable接口。
     * 而且,所有这些键必须是相互可比的:k1. compareto (k2)不能为map中的任何键k1和k2抛出ClassCastException。
     * 此方法在n*log(n)时间内运行。
     *
     * @param  m the map whose mappings are to be placed in this map
     * @throws ClassCastException if the keys in m are not {@link Comparable},
     *         or are not mutually comparable
     * @throws NullPointerException if the specified map is null
     */
    public TreeMap(Map m) {
        comparator = null;
        putAll(m);
    }

    /**
     * 构造一个包含相同映射的新树映射,并使用与指定SortedMap相同的顺序。
     * 这种方法在线性时间内运行。
     *
     * @param  m the sorted map whose mappings are to be placed in this map,
     *         and whose comparator is to be used to sort this map
     * @throws NullPointerException if the specified map is null
     */
    public TreeMap(SortedMap m) {
    	// comparator为m的comparator
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }

查询方法 size,containsKey,containsValue,get,comparator,firstKey,lastKey

    // Query Operations

    /**
     * 返回此映射中的键值映射的数目。
     *
     * @return the number of key-value mappings in this map
     */
    public int size() {
        return size;
    }

    /**
     * 如果此映射包含指定键的映射,则返回true。
     *
     * @param key key whose presence in this map is to be tested
     * @return {@code true} if this map contains a mapping for the
     *         specified key
     * @throws ClassCastException if the specified key cannot be compared
     *         with the keys currently in the map
     * @throws NullPointerException if the specified key is null
     *         and this map uses natural ordering, or its comparator
     *         does not permit null keys
     */
    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

    /**
     * 如果此映射将一个或多个键映射到指定的值,则返回true。
     * 更正式地说,当且仅当此映射包含至少一个到值v的映射(value==null ?v = = null: value.equals (v))。
     * 对于大多数实现,此操作可能需要映射大小的时间线性。
     *
     * @param value value whose presence in this map is to be tested
     * @return {@code true} if a mapping to {@code value} exists;
     *         {@code false} otherwise
     * @since 1.2
     */
    public boolean containsValue(Object value) {
    	// 从第一个entry开始,不断e = successor(e))循环
        for (Entry e = getFirstEntry(); e != null; e = successor(e))
            if (valEquals(value, e.value))
                return true;
        return false;
    }

    /**
     * 返回指定键映射到的值,如果该映射不包含键的映射,则返回null。
     *
     * 

更正式地说,如果这个映射包含一个从键k到值v的映射, * 使得键根据映射的顺序与k进行比较,两者相同,那么这个方法将返回v;否则返回null。 * (最多可以有一个这样的映射。) * *

返回值为null并不一定表示映射不包含键的映射;映射也可有value为null。 * containsKey操作可以用来区分这两种情况。 * * @throws ClassCastException if the specified key cannot be compared * with the keys currently in the map * @throws NullPointerException if the specified key is null * and this map uses natural ordering, or its comparator * does not permit null keys */ public V get(Object key) { // 根据getEntry方法 Entry p = getEntry(key); return (p==null ? null : p.value); } public Comparator comparator() { return comparator; } /** * @throws NoSuchElementException {@inheritDoc} */ public K firstKey() { return key(getFirstEntry()); } /** * @throws NoSuchElementException {@inheritDoc} */ public K lastKey() { return key(getLastEntry()); }

查询的辅助方法  8个getXXXEntry和getEntryXXX ,successor,predecessor

    /**
     * 返回给定键的entry,如果映射不包含键的entry,则返回null。
     *
     * @return this map's entry for the given key, or {@code null} if the map
     *         does not contain an entry for the key
     * @throws ClassCastException if the specified key cannot be compared
     *         with the keys currently in the map
     * @throws NullPointerException if the specified key is null
     *         and this map uses natural ordering, or its comparator
     *         does not permit null keys
     */
    final Entry getEntry(Object key) {
    	// 为了性能考虑,卸载基于比较器的版本
        if (comparator != null)
            return getEntryUsingComparator(key);
        // key不能为null
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
        // key变为comparable类型
            Comparable k = (Comparable) key;
        Entry p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            // 小于0,p为左孩子,大于0,p为右孩子
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
            	// 如果比较结果为0,则返回当前节点
                return p;
        }
        return null;
    }

    /**
     * 使用比较器的getEntry版本。从getEntry中分离出来。
     * (对于不太依赖比较器性能的大多数方法来说,这样做是不值得的,但是在这里是值得的。)
     */
    final Entry getEntryUsingComparator(Object key) {
        @SuppressWarnings("unchecked")
            K k = (K) key;
        Comparator cpr = comparator;
        if (cpr != null) {
            Entry p = root;
            while (p != null) {
            	// 使用treemap里面的comparator进行比较,其余相同
                int cmp = cpr.compare(k, p.key);
                if (cmp < 0)
                    p = p.left;
                else if (cmp > 0)
                    p = p.right;
                else
                    return p;
            }
        }
        return null;
    }

    /**
     * 获取与指定键对应的项;如果不存在这样的项,则返回大于指定键的最小键的项;
     * 如果不存在这样的条目(即,则树中最大的键值小于指定的键值),返回null。
     */
    final Entry getCeilingEntry(K key) {
        Entry p = root;
        while (p != null) {
            int cmp = compare(key, p.key);
            if (cmp < 0) {
            	// key小于p,p大于key
                if (p.left != null)
                    p = p.left;
                else
                	// 如果没有左孩子,代表p是刚刚大于key的节点
                    return p;
            } else if (cmp > 0) {
            	// key大于p,p小于key
                if (p.right != null) {
                    p = p.right;
                } else {
                	// 如果没有右孩子,p是刚刚小于key的节点,找到比p稍微大点的节点
                	//     6
                	//  4     8
                	// 2  5  7  9
                	// 如果p是2,返回4,如果p是5,返回6
                	// 即返回p的第一个左孩子是,p的祖先节点(包括p),的祖先,
                    Entry parent = p.parent;
                    Entry ch = p;
                    while (parent != null && ch == parent.right) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    return parent;
                }
            } else
            	// 如果相同,返回该节点
                return p;
        }
        return null;
    }

    /**
     * 获取与指定键对应的项;
     * 如果不存在这样的项,则返回小于指定键的最大键的项;
     * 如果不存在这样的条目,则返回null。
     */
    final Entry getFloorEntry(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 (cmp < 0) {
                if (p.left != null) {
                    p = p.left;
                } else {
                	// 如果没有左孩子,p是刚刚大于key的节点,key小于p,找到比p稍微小于点的节点
                	//     6
                	//  4     8
                	// 2  5  7  9
                	// 如果p是5,返回4,如果p是7,返回6
                	// 即返回p的第一个右孩子是,p的祖先节点(包括p),的祖先,
                    Entry parent = p.parent;
                    Entry ch = p;
                    while (parent != null && ch == parent.left) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    return parent;
                }
            } else
                return p;

        }
        return null;
    }

    /**
     * 获取大于指定键的最小键的项;
     * 如果不存在这样的项,则返回大于指定键的最小键的项;
     * 如果不存在这样的条目,则返回null。
     */
    final Entry getHigherEntry(K key) {
        Entry p = root;
        while (p != null) {
            int cmp = compare(key, p.key);
            if (cmp < 0) {
                if (p.left != null)
                    p = p.left;
                else
                    return p;
            } else {
                if (p.right != null) {
                    p = p.right;
                } else {
                    Entry parent = p.parent;
                    Entry ch = p;
                    while (parent != null && ch == parent.right) {
                        ch = parent;
                        parent = parent.parent;
                    }
                    return parent;
                }
            }
        }
        return null;
    }

    /**
     * 返回小于指定键的最大键的项;
     * 如果不存在这样的条目(即,则树中最小的键值大于指定的键值),返回null。
     */
    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;
    }
    /**
     * 返回TreeMap中的第一个条目(根据TreeMap的键排序函数)。如果树形图为空,则返回null。
     */
    final Entry getFirstEntry() {
        Entry p = root;
        if (p != null)
        	// 找到最左节点
            while (p.left != null)
                p = p.left;
        return p;
    }

    /**
     * 返回TreeMap中的最后一个条目(根据TreeMap的键排序函数)。如果树形图为空,则返回null。
     */
    final Entry getLastEntry() {
        Entry p = root;
        if (p != null)
            while (p.right != null)
                p = p.right;
        return p;
    }

    /**
     * 返回指定项的继承项,如果没有继承项,则返回null。(即刚刚大于t的entry)
     */
    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 {
        	// 如果没有右孩子
        	//     6
        	//  4     8
        	// 2  5  7  9
        	// 如果p是2,返回4,如果p是5,返回6
        	// 即返回p的第一个左孩子是,p的祖先节点(包括p),的祖先,
            Entry p = t.parent;
            Entry ch = t;
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }

    /**
     * 返回指定项的前任,如果没有,则返回null。
     */
    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;
        }
    }

put方法

    /**
     * 将指定值与此映射中的指定键关联。
     * 如果映射之前包含键的映射,则替换旧值。
     * 如果指定key是null,并且map使用自然排序。或者它的comparator不允许null的key,会抛出NullPointerException。
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     *
     * @return the previous value associated with {@code key}, or
     *         {@code null} if there was no mapping for {@code key}.
     *         (A {@code null} return can also indicate that the map
     *         previously associated {@code null} with {@code key}.)
     * @throws ClassCastException if the specified key cannot be compared
     *         with the keys currently in the map
     * @throws NullPointerException 如果指定key是null,并且map使用自然排序。或者它的comparator不允许null的key。
     */
    public V put(K key, V value) {
        Entry t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check 类型(和可能为null)的检查
            // 初始化root节点
            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry parent;
        // comparator和comparable的情况分开来
        Comparator cpr = comparator;
        if (cpr != null) {
            do {
            	// 每次记录下parent,然后t跑到孩子处
                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);
                // 如果没找到,t到了应该到的孩子处,为null,parent为t的父节点
            } 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);
        }
        // 没有找到节点,在parent处增加孩子
        Entry e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

你可能感兴趣的:(源码分析,java容器)