【Java8源码分析】集合框架-TreeMap

来源:互联网 发布:阿里云机房在哪里 编辑:程序博客网 时间:2024/05/16 08:52

一、红黑树原理

TreeMap是基于红黑树实现的。

一棵高度为h的二叉搜索树,它可以支持任何一种基本动态集合操作,其时间复杂度均为O(h)。当h较小时,执行会比较快。红黑树是许多“平衡”搜索树中的一种。



(1)性质

树中的结点有5个属性:color,key,key,left,right和p,满足以下五大性质:

  • 每个结点或是Red,或是Black
  • 根结点是Black的
  • 每个叶结点NIL是Black的
  • 如果一个结点是Red,则它的两个结点都是black
  • 对每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的Black结点

(2)旋转

一棵含有n个关键字的红黑树上,搜索树操作插入和删除话费时间在O(lgn)。这两个操作对树做了修改,可能违反红黑性质,为维护这些性质,需改变树中结点颜色以及指针结构,一般通过旋转操作。



二、存储结构

    static final class Entry<K,V> implements Map.Entry<K,V> {        K key;        V value;        Entry<K,V> left;        Entry<K,V> right;        Entry<K,V> parent;        boolean color = BLACK;        Entry(K key, V value, Entry<K,V> parent) {            this.key = key;            this.value = value;            this.parent = parent;        }        public K getKey() {            return key;        }        public V getValue() {            return value;        }        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;        }    }

三、代码分析

(1)属性域

    // 比较器    private final Comparator<? super K> comparator;    // 根节点    private transient Entry<K,V> root;    private transient int size = 0;    // 实现fast-fail机制,跟ArrayList、LinkedList类似    private transient int modCount = 0;

(2)构造函数

    // 构造函数    public TreeMap() {        comparator = null;    }    // 带比较器    public TreeMap(Comparator<? super K> comparator) {        this.comparator = comparator;    }    public TreeMap(Map<? extends K, ? extends V> m) {        comparator = null;        // 调用putAll把所有元素添加进去        putAll(m);    }    public TreeMap(SortedMap<K, ? extends V> m) {        comparator = m.comparator();        try {            // 此方法为从排序集合中构造TreeMap,复杂度为线性            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);        } catch (java.io.IOException cannotHappen) {        } catch (ClassNotFoundException cannotHappen) {        }    }    public void putAll(Map<? extends K, ? extends V> map) {        int mapSize = map.size();        // 如果TreeMap为空,且map为SortedMap        // 则调用从有序集合中构造TreeMap方法        if (size==0 && mapSize!=0 && map instanceof SortedMap) {            Comparator<?> c = ((SortedMap<?,?>)map).comparator();            // 如果比较器一样,才执行,否则调用putAll            if (c == comparator || (c != null && c.equals(comparator))) {                ++modCount;                try {                    // 调用从Sorted构造                    buildFromSorted(mapSize, map.entrySet().iterator(),                                    null, null);                } catch (java.io.IOException cannotHappen) {                } catch (ClassNotFoundException cannotHappen) {                }                return;            }        }        // 其他情况执行以下代码        // 内部调用了put,put为TreeMap的添加元素函数        super.putAll(map);    }    // 从排序序列中构造TreeMap,线性时间    private void buildFromSorted(int size, Iterator<?> it,                                 java.io.ObjectInputStream str,                                 V defaultVal)        throws  java.io.IOException, ClassNotFoundException {        this.size = size;        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),                               it, str, defaultVal);    }    // 真正的从排序序列中构造TreeMap函数    @SuppressWarnings("unchecked")    private final Entry<K,V> buildFromSorted(int level, int lo, int hi,                                             int redLevel,                                             Iterator<?> it,                                             java.io.ObjectInputStream str,                                             V defaultVal)        throws  java.io.IOException, ClassNotFoundException {        // 策略:树的根节点肯定是排序序列的中间树        // 递归处理根节点的左树、右树        if (hi < lo) return null;        int mid = (lo + hi) >>> 1;        Entry<K,V> left  = null;        if (lo < mid)            left = buildFromSorted(level+1, lo, mid - 1, redLevel,                                   it, str, defaultVal);        // extract key and/or value from iterator or stream        K key;        V value;        if (it != null) {            if (defaultVal==null) {                Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next();                key = (K)entry.getKey();                value = (V)entry.getValue();            } else {                key = (K)it.next();                value = defaultVal;            }        } else { // use stream            key = (K) str.readObject();            value = (defaultVal != null ? defaultVal : (V) str.readObject());        }        Entry<K,V> middle =  new Entry<>(key, value, null);        // color nodes in non-full bottommost level red        if (level == redLevel)            middle.color = RED;        if (left != null) {            middle.left = left;            left.parent = middle;        }        if (mid < hi) {            Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,                                               it, str, defaultVal);            middle.right = right;            right.parent = middle;        }        return middle;    }

(3)查找

    final Entry<K,V> getEntry(Object key) {        if (comparator != null)            return getEntryUsingComparator(key);        // TreeMap的key值不能为null        if (key == null)            throw new NullPointerException();        // 如果未定义Comparator,则采用key的实现的Comparable        @SuppressWarnings("unchecked")            Comparable<? super K> k = (Comparable<? super K>) key;        Entry<K,V> p = root;        while (p != null) {            // 由根开始查找,小左大右            int cmp = k.compareTo(p.key);            if (cmp < 0)                p = p.left;            else if (cmp > 0)                p = p.right;            else                return p;        }        return null;    }    // 带有Comparator比较器的查询,原理跟上面类似    final Entry<K,V> getEntryUsingComparator(Object key) {        @SuppressWarnings("unchecked")            K k = (K) key;        Comparator<? super K> cpr = comparator;        if (cpr != null) {            Entry<K,V> p = root;            while (p != null) {                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;    }

(4)添加

    public V put(K key, V value) {        Entry<K,V> t = root;        if (t == null) {            // 检查是否为null,再次提醒,key值不能为null            compare(key, key);            root = new Entry<>(key, value, null);            size = 1;            modCount++;            return null;        }        int cmp;        Entry<K,V> parent;        Comparator<? super K> 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                    // 如果key值相等,覆盖,返回旧值                    return t.setValue(value);            } while (t != null);        }        // 无比较器        else {            if (key == null)                throw new NullPointerException();            @SuppressWarnings("unchecked")                Comparable<? super K> k = (Comparable<? super K>) 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<K,V> e = new Entry<>(key, value, parent);        if (cmp < 0)            parent.left = e;        else            parent.right = e;        // 此函数为插入元素后,有可能破坏红黑树性质        // 故需要旋转节点来修复红黑树        fixAfterInsertion(e);        size++;        modCount++;        return null;    }

(5)删除

    // 删除的函数比较复杂一些,主要需要考虑多种情况    // 具体说明可参考算法导论一书    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;            }        }    }

四、总结

  • TreeMap是根据key进行排序的,它的排序和定位需要依赖比较器或覆写Comparable接口,也因此不需要key覆写hashCode方法和equals方法,就可以排除掉重复的key,而HashMap的key则需要通过覆写hashCode方法和equals方法来确保没有重复的key
  • TreeMap的查询、插入、删除效率均没有HashMap高,一般只有要对key排序时才使用TreeMap
  • TreeMap的key不能为null,而HashMap的key可以为null

五、参考

http://blog.csdn.net/ns_code/article/details/36421085