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

一、红黑树原理

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

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linxdcn/article/details/72611660
文章标签: java 源码
个人分类: Java8源码分析
所属专栏: Java8源码分析
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭