TreeMap源码解析

本文详细探讨了TreeMap在Java中的实现,特别是其基于红黑树的数据结构。文章提到了TreeMap如何实现排序功能,以及与LinkedList, ArrayList, HashMap等的区别。内容包括构造器、put、get、remove操作,重点解析了clear()方法的工作原理。同时,文章介绍了TreeMap的各种内部类,如Entry、迭代器和SubMap,以及学习红黑树过程中的一些陷阱。" 110701633,10294764,Python Matplotlib:如何实现曲面图颜色渐变,"['Python编程', '数据可视化', 'matplotlib库', '3D绘图']
摘要由CSDN通过智能技术生成

疑问:TreeMap的clear()方法与LinkedList,ArrayList,HashMapd等的比较

一、定义

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable

TreeMap扩展自AbstractMap
实现NavigableMap
实现Cloneable,实现Serializable
来看下NavigableMap

public interface SortedMap<K,V> extends Map<K,V> {
    Comparator<? super K> comparator();

    //返回formKey到toKey(不包括)间的视图
    SortedMap<K,V> subMap(K fromKey, K toKey);

    //返回小于toKey的视图
    SortedMap<K,V> headMap(K toKey);

    //返回小于tailMap的视图
    SortedMap<K,V> tailMap(K fromKey);

    //返回first key
    K firstKey();

    //返回last key
    K lastKey();

    //返回key视图,与SortMap存在映射关系,修改set<K>或SortedMap中的一个,另一个也会改变
    Set<K> keySet();

    Collection<V> values();

    Set<Map.Entry<K, V>> entrySet();
}

public interface NavigableMap<K,V> extends SortedMap<K,V> {
    Map.Entry<K,V> lowerEntry(K key);

    K lowerKey(K key);

    Map.Entry<K,V> floorEntry(K key);

    K floorKey(K key);

    Map.Entry<K,V> ceilingEntry(K key);

    K ceilingKey(K key);

    Map.Entry<K,V> higherEntry(K key);

    K higherKey(K key);

    Map.Entry<K,V> firstEntry();

    Map.Entry<K,V> lastEntry();

    Map.Entry<K,V> pollFirstEntry();

    Map.Entry<K,V> pollLastEntry();

    //返回逆序视图
    NavigableMap<K,V> descendingMap();

    NavigableSet<K> navigableKeySet();

    //逆序key视图
    NavigableSet<K> descendingKeySet();

    //根据formInclusive判断返图视图是否包含formKey
    //根据toInclusive判断返图视图是否包含toKey
    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                             K toKey,   boolean toInclusive);

    //根据toInclusive判断返图视图是否包含toKey
    NavigableMap<K,V> headMap(K toKey, boolean inclusive);

    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);

    SortedMap<K,V> subMap(K fromKey, K toKey);

    SortedMap<K,V> headMap(K toKey);

    SortedMap<K,V> tailMap(K fromKey);
}

SortMap和SortedMap提供了一些排序需要基本方法。

二、底层
红黑树
恶补这块花费了很久时间。。
理解红黑树的时候有个坑,在这里记录一下:TreeMap中的红黑树叶节点都是空节点,都不存储数据,只要不是叶节点都会存储数据。
三、构造器及常量

//comparator比较器,为null时,按照自然顺序排序
    private final Comparator<? super K> comparator;

    //根root
    private transient Entry<K,V> root = null;

    //size
    private transient int size = 0;

    //多线程是舒勇
    private transient int modCount = 0;

    //空tree,自然顺序排序
    public TreeMap() {
        comparator = null;
    }

    //空tree,通过comparator来比较
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

    //tree中m包含entry,entrys按照自然排序重新进行排序,
    //运行时间为 n*log(n)。 
    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }

    //运行时间n
    //生成TreeMap的结构满足平衡二叉树,可能和m的结构不一致
    public TreeMap(SortedMap<K, ? extends V> m) {
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }
    //通过递归生成一个平衡二叉树
    //生产二叉树的结构:最高层节点颜色都为red,其余black
    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);
    }

    /*
     * 通过递归获取从lo-hi见的节点树,返回树的跟
     */
    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 {
        /*
         * Strategy: The root is the middlemost element. To get to it, we
         * have to first recursively construct the entire left subtree,
         * so as to grab all of its elements. We can then proceed with right
         * subtree.
         *
         * The lo and hi arguments are the minimum and maximum
         * indices to pull out of the iterator or stream for current subtree.
         * They are not actually indexed, we just proceed sequentially,
         * ensuring that items are extracted in corresponding order.
         */

        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) {
                //val为空,说明it类型为Entry,通过Entry获得value值
                Map.Entry<K,V> entry = (Map.Entry<K,V>)it.next();
                key = entry.getKey();
                value = entry.getValue();
            } else {
                //val不为空,value直接赋值
                key = (K)it.next();
                value = defaultVal;
            }
        } else { //通过流取值
            key = (K) str.readObject();
            value = (defaultVal != null ? defaultVal : (V) str.readObject());
        }

        Entry<K,V> middle =  new Entry<>(key, value, null);

        // level == redLevel ,则此时的结点为红色 
        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;
    }

    //获取叶子节点的层数
    private static int computeRedLevel(int sz) {
        int level = 0;
        for (int m = sz - 1; m >= 0; m = m / 2 - 1)
            level++;
        return level;
    }

三、put,get、remove

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

    final Entry<K,V> getEntry(Object key) {
        // 按自然顺序排序时,调用getEntryUsingComparator,两者的性能并没有差异
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        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;

    public void putAll(Map<? extends K, ? extends V> map) {
        int mapSize = map.size();
        if (size==0 && mapSize!=0 && map instanceof SortedMap) {
            Comparator c = ((SortedMap)map).comparator();
            if (c == comparator || (c != null && c.equals(comparator))) {
                ++modCount;
                try {
                    buildFromSorted(mapSize, map.entrySet().iterator(),
                                    null, null);
                } catch (java.io.IOException cannotHappen) {
                } catch (ClassNotFoundException cannotHappen) {
                }
                return;
            }
        }
        super.putAll(map);
    }

    //do-wile的典型用法哦
    public V put(K key, V value) {
        Entry<K,V> t = root;
        //第一种情况,tree为空
        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<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        //找到插入节点的位置
        if (cpr != null) {
            //使用do-while,因为上面已经比较t==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();
            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);
        //将e插入到tree中,然后进行调整
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

     /**
     * 求t的下一个节点,
     */
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            return null;
        //当t有右子节点时,t的下一个节点在以t.right为根的树中
        else if (t.right != null) {
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        //t没有右子节点,t的下一个节点在为t的父辈节点中
        } else {
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            //parent = null,遍历完成,没有next值
            //p.parent.right = p 时,说明t.parent < p,需要继续向上遍历
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }
    private void rotateLeft(Entry<K,V> p) {
        if (p != null) {
            Entry<K,V> r = p.right;
            //右节点指向右节点。left
            p.right = r.left;
            if (r.left != null)
                //右节点。left.parent指向p
                r.left.parent = p;
            //右节点。parent指向p,parent
            r.parent = p.parent;
            if (p.parent == null)
                //P为根节点,跟节点为右节点
                root = r;
            else if (p.parent.left == p)
                //将父节点指向p改为指向右节点
                p.parent.left = r;
            else
                p.parent.right = r;
            //右节点。left指向p
            r.left = p;
            //p.parent指向右节点
            p.parent = r;
        }
    }
    /** From CLR */
    //设计很灵巧,自己的想法是一直判断,需要的时候递归,或者像责任链模式那样逐层像下

    //第五种情况和第四种情况直接写在一个代码块中,第五种情况右单独写在一个if代码块中,
    //这样的化,如果是第五种情况,执行if代码块后,变为第四种情况,直接执行第四种情况的代码块,

    //操作时,颜色调整log(n)此,旋转最多2次
    private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED;
        //第二种情况 父节点black时,不需要改变
        //第三、四。。情况下父节点red,祖父节点一定为black

        //只有第三中情况会进行循环
        //x==null表明: 上次循环时,x.parant为root 循环结束
        //x==root 循环结束
        while (x != null && x != root && x.parent.color == RED) {
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    //第三种情况:父节点为祖父节点的左子节点,且叔节点red
                    //此时改变父节点、叔节点、祖父节点颜色,以祖父节点为根的子树符合标准,继续递归
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == rightOf(parentOf(x))) {
                        //第五中情况:父节点为祖父节点的左子节点,且叔节点black,节点为父节点的右节点几点
                        //此时以父节点左旋,将节点重新赋值为父节点,变为第4种情况,
                        //然后直接执行第四种情况的操作
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    //第四种情况:父节点为祖父节点的左子节点,且叔节点black,节点为父节点的左几点
                    //此时以祖父节点右旋,然后改变节点颜色,完成
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;
    }

    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;

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

     * 第三种情况右疑问
     * 
     * 颜色转换log(n),旋转最多3次
     * 
     * 将调整删除节点后的调整 和 第三种情况,未删除节点前直接调整,放在同一个方法中,难理解
     */
    private void deleteEntry(Entry<K,V> p) {
        modCount++;
        size--;

        //第六种情况:拥有两个节点,与节点的next互换位置后,变为第2-5钟情况
        //只喜欢key,value值,其他值保留
        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

        Entry<K,V> replacement = (p.left != null ? p.left : p.right);

        if (replacement != null) {
            //第四种情况:拥有一个子节点,且节点red
            //直接删除节点
            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;

            p.left = p.right = p.parent = null;

            // Fix replacement
            if (p.color == BLACK)
                //第五种情况:拥有一个子节点,且节点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)
                //第三种情况,没有子节点,且节点black
                //通过调整,调整后变为第二种情况
                //但是,p的指针指向不是变为root了吗??
                fixAfterDeletion(p);

            if (p.parent != null) {
                //第二种情况,没有子节点,且节点red
                //此时,直接删除节点
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }

    /** From CLR */
    //通过调整使x.parent到x下面节点路径上的黑节点数都增加1
    private void fixAfterDeletion(Entry<K,V> x) {
        while (x != root && colorOf(x) == BLACK) {
            if (x == leftOf(parentOf(x))) {
                Entry<K,V> sib = rightOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    //第一种情况:兄弟节点red,则其他节点都black
                    //以父节点,左旋,改变父节点red,兄弟节点black,变为第三、四、五种情况
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    sib = rightOf(parentOf(x));
                }

                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    //第二种情况,兄弟节点black,兄弟节点两个子节点black
                    //改变兄弟节点red,此时父节点为根的子树,都少一个黑节点,继续递归
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(rightOf(sib)) == BLACK) {
                        //第四种情况,兄弟节点black,兄弟节点的左子节点red,右子节点blac
                        //改变兄弟节点的左子节点black,兄弟节点red,以兄弟节点右旋,变为第五种情况
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    //第五种情况:兄节点black,兄节点的右子节点red,左子节点black
                    //兄弟节点颜色改变为父节点颜色,父节点颜色black,兄节点的右子节点red,以父节点左旋,完成
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                }
            } else { // symmetric
                Entry<K,V> sib = leftOf(parentOf(x));

                if (colorOf(sib) == RED) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                }

                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(leftOf(sib)) == BLACK) {
                        setColor(rightOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    }
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                }
            }
        }

        //??
        setColor(x, BLACK);
    }

五、clear

/**
     * 直接root变为null,其他交给gc
     * 为什么不逐个元素清空?他们之间也有引用
     * 虚拟机基本了解后再来解决吧
     */
    public void clear() {
        modCount++;
        size = 0;
        root = null;
    }

六、内部类
TreeMap的内部类特别多
这里写图片描述
这里写图片描述
Entry:基本元素类
Values,KeySet,EntrySet: 用于生成集合,多数方式都是通过代理利用外部类的方法。
PrivateEntryIterator,KeyIterator,ValueIterator,EntryIterator,DescendingKeyIterator:迭代器类
SubMap:为了与以前的代码兼容
NavigableSubMap、AscendingSubMap、DescendingSubMap: 为了生成subMap,AscendingSubMap、DescendingSubMap继承与NavigableSubMap,NavigableSubMap基本实现了TreeMap的所有功能,并且嵌套了更多的静态内部类

红黑树看的头疼。。

参考:http://blog.csdn.net/jzhf2012/article/details/8540713
http://blog.csdn.net/jiang_bing/article/details/7537803
https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91
http://yikun.github.io/2015/04/06/Java-TreeMap%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%8F%8A%E5%AE%9E%E7%8E%B0/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值