TreeMap源码解析

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

HashMap继承抽象类AbstractMap,实现了NavigableMap接口,NavigableMap继承自SortedMap,方法有lowerEntry小于,floorEntry小于等于,ceilingEntry大于,higherEntry大于等于,便于搜索查找。

  • TreeMap的属性
    private final Comparator<? super K> comparator;                 //保存顺序的比较器,
    private transient Entry<K,V> root = null;                       //根节点
    private transient int size = 0;                                 //树中的节点数量
    private transient int modCount = 0;
    private static final boolean RED   = false;
    private static final boolean BLACK = true;
  • TreeMap的构造方法
    public TreeMap() {
        comparator = null;                                          //comparator为空,即采用自然顺序维持TreeMap中节点的顺序
    }
    public TreeMap(Comparator<? super K> comparator) {              //带有比较器的构造方法
        this.comparator = comparator;
    }
    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);                                                  //调用putAll方法将Map中的所有元素加入到TreeMap中
    }
    public TreeMap(SortedMap<K, ? extends V> m) {                   //根据SortedMap的比较器维持TreeMap中的节点顺序
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);         //SortedMap中的内容添加到TreeMap中
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }
  • 静态内部类
    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;                                              //键
        V value;                                            //值
        Entry<K,V> left = null;                             //左节点
        Entry<K,V> right = null;                            //右节点
        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;
        }
    }

put

    public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {                                //根节点为null,则直接插入根节点
            compare(key, key);
            root = new Entry<>(key, value, null);       //创建个新的entry节点,指向root
            size = 1;                                   //当前容量是1
            modCount++;
            return null;
        }
        int cmp;                                         //cmp表示key排序的返回结果
        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
                    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);                     //新建红黑树节点
        if (cmp < 0)                                                        //小于parent的key,则当做左子节点 
            parent.left = e;
        else
            parent.right = e;                                               //大于parent的key,则当做右子节点 
        fixAfterInsertion(e);                                               //恢复红黑树的特性
        size++;
        modCount++;
        return null;
    }
    final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }
     /** From CLR */
    private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED;

        while (x != null && x != root && x.parent.color == RED) {   //循环 节点不为null且不为根节点且节点的父节点是红色
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {     //当前节点的父节点是当前节点的爷爷节点的的左节点(叔叔节点)
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));      //获取当前节点的叔叔节点(爷爷有且只有2个孩子,左是父节点,右是叔节点)
                if (colorOf(y) == RED) {                            //假如叔叔节点是红色
                    setColor(parentOf(x), BLACK);                   //设置父节点是黑色
                    setColor(y, BLACK);                             //设置叔叔节点是黑色
                    setColor(parentOf(parentOf(x)), RED);           //设置爷爷节点是红色
                    x = parentOf(parentOf(x));                      //将爷爷节点指向当前节点
                } else {                                            //当前节点的父节点是当前节点的爷爷节点的的右节点(叔叔节点)
                    if (x == rightOf(parentOf(x))) {                //当前节点是其父节点的右节点
                        x = parentOf(x);                            //父节点指向当前节点
                        rotateLeft(x);                              //左旋
                    }
                    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;                                         //根节点设置为黑色
    }


    private void rotateLeft(Entry<K,V> p) {                         //左旋
        if (p != null) {
            Entry<K,V> r = p.right;                                 
            p.right = r.left;                                       
            if (r.left != null)                                     
                r.left.parent = p;                                  
            r.parent = p.parent;
            if (p.parent == null)
                root = r;
            else if (p.parent.left == p)
                p.parent.left = r;
            else
                p.parent.right = r;
            r.left = p;
            p.parent = r;
        }
    }
    private void rotateRight(Entry<K,V> p) {                        //右旋
        if (p != null) {
            Entry<K,V> l = p.left;
            p.left = l.right;
            if (l.right != null) l.right.parent = p;
            l.parent = p.parent;
            if (p.parent == null)
                root = l;
            else if (p.parent.right == p)
                p.parent.right = l;
            else p.parent.left = l;
            l.right = p;
            p.parent = l;
        }
    }
添加一组数据来讲解吧,注释写不下去了-_-! 

eg:

        TreeMap m = new TreeMap();
    	m.put(2,1);
    	m.put(3,2);
    	m.put(5,3);
    	m.put(6,4);
    	m.put(8,5);
    	m.put(9,6);
    	m.put(10,7);
        m.put(1,8);
按顺序添加,先添加key为2的数据,put方法,root为null,创建一个节点,节点的color属性默认是黑色,这次2是根节点,如下图

image

添加key为3后,如下图

image
默认的比较器,比较key,3比2大,所以放到右边。fixAfterInsertion后,将key设置为红色,root节点设置为黑色。

添加key为5后,如下图

image
比较key,5比2大,所以放到右边,比3也大,就放3右边了,fixAfterInsertion后,if判断leftOf(parentOf(parentOf(x))=null,parentOf(x)是key为3的节点,
进入到else判断,leftOf(parentOf(parentOf(x)))=null,colorOf(y)=BLACK进入else判断,leftOf(parentOf(x))=null,不会进入到if判断,将当前节点5的父
节点3设置为黑色,将爷爷节点2设置为红色,进行左旋操作,左旋是将根节点2作为参数,传进去的,左旋后,3变成了根节点,2变成了3的左子节点。

添加key为6后,如下图

image
比较key,6比3大,所以放到右边,比5也大,就放5右边了,fixAfterInsertion后,if判断leftOf(parentOf(parentOf(x))=null,parentOf(x)是key为5的节点,
进入到else判断,leftOf(parentOf(parentOf(x)))是节点2,color是红色的,colorOf(y) == RED进入if判断,将当前节点6的父节点5设置为黑色,将节点2设置为黑色,
将当前节点6的爷爷节点3设置为红色,将爷爷节点指向3,跳出循环,设置根节点为黑色。

添加key为8后,如下图

image
比较key,8比3大,放到右边,比5也大,放右边,比6也大,放6右边,fixAfterInsertion后,if判断leftOf(parentOf(parentOf(x))=null,
parentOf(x)是key为6的节点,进入到else判断,leftOf(parentOf(parentOf(x)))是节点2,color是黑色的,进入else判断,leftOf(parentOf(x)为null,
不等于当前x节点,将当前节点8的父节点6设置为黑色,将爷爷节点5设置为红色,进行左旋操作,左旋是将爷爷节点5作为参数,传进去的,左旋后,5变成了6的左子节点,6变成3的右节点。

添加key为9后,如下图

image
比较key,9比3大,放到右边,比6大,放右边,比8大,放右边,fixAfterInsertion后,if判断leftOf(parentOf(parentOf(x))是key为5的节点,parentOf(x)是key为8的节点,进入到else判断,leftOf(parentOf(parentOf(x)))是节点5,color是红色,进入if判断,将当前x节点的父节点8设置为黑色,将节点5设置为黑色,将当前节点的爷爷节点
6设置为红色,将爷爷节点6指向当前插入节点9,此时x节点是节点6了,x.parent.color是黑色,所以跳出循环,设置根节点为黑色。

添加key为10后,如下图

image
比较key,10比3大,放到右边,比6大,放右边,比8大,放右边,比9大,放右边,fixAfterInsertion后,if判断leftOf(parentOf(parentOf(x)),key8的左子节点是空,parentOf(x)是key为9的节点,进入到else判断,leftOf(parentOf(parentOf(x)))是空,进入else判断,leftOf(parentOf(x))是空,不等于当前节点x,设置当前节点10的父节点9为黑色,当前节点10的爷爷节点8为红色,进行左旋操作,左旋是将爷爷节点8作为参数,传进去的,左旋后,8变成了9的左子节点,9变成6的右节点。

添加key为1后,如下图

image
比较key,1比3小,放到左边,比2小,放左边,fixAfterInsertion后,x.parent.color,x.parent是节点2,是黑色的,所以没进入循环,设置根节点是黑色就结束了。

总结下特点:
1.根节点总是黑色。
2.新插入的节点是默认是黑色,在经过fixAfterInsertion方法后,会变成红色。
3.fixAfterInsertion方法:当前节点不是空,不是根节点,父节点是红色才会进行调整操作。(一个路径上不能有2个红色相邻的节点)
4.根节点到所有叶子节点的数量必须相同(上例put方法,key为5,为了保持平衡进行左旋操作)

remove

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

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }
    private void deleteEntry(Entry<K,V> p) {
        modCount++;
        size--;

        if (p.left != null && p.right != null) {        //被删除节点的左子节点和右子节点都不为空,则用p节点的中序后继节点代替p节点 
            Entry<K,V> s = successor(p);                //寻找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) {                                          //替代节点不为空
            replacement.parent = p.parent;          
            if (p.parent == null)                                          
                root = replacement;                                          //p节点没有父节点,替代节点作根节点
            else if (p == p.parent.left)
                p.parent.left  = replacement;                               //P为左节点,则用replacement来替代为左节点 
            else
                p.parent.right = replacement;                               //P为右节点,则用replacement来替代为右节点  

            p.left = p.right = p.parent = null;                             //P节点从这棵树中剔除掉

            if (p.color == BLACK)                       
                fixAfterDeletion(replacement);                              //P为黑色,则需要调整红黑树
        } else if (p.parent == null) { // return if we are the only node.
            root = null;                                                    //P为根节点,直接删除 
        } else {                                                            //P节点不存在子节点,直接删除
            if (p.color == BLACK)
                fixAfterDeletion(p);                                        //P节点的颜色为黑色,调整红黑树

            if (p.parent != null) {                                         //删除P节点
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            }
        }
    }
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            return null;
        else if (t.right != null) {                                     //寻找右子节点的最左子节点
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        } else {                                                        //寻找左子节点的最右子节点
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }
    /** From CLR */
    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) {
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    sib = rightOf(parentOf(x));
                }

                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) {
                    setColor(sib, RED);
                    x = parentOf(x);
                } else {
                    if (colorOf(rightOf(sib)) == BLACK) {
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    }
                    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);
    }

eg:

        TreeMap m = new TreeMap();
    	m.put(2,1);
    	m.put(3,2);
    	m.put(5,3);
    	m.put(6,4);
    	m.put(8,5);
    	m.put(9,6);
    	m.put(10,7);
        m.put(1,8);
        m.remove(3);
        m.remove(9);
        m.remove(1);
删除根节点3,如下图

image
判断节点3,有没有左子节点和右子节点,优先寻找右子节点的最左子节点,没有右子节点,则寻找寻找左子节点的最右子节点,节点3的右子节点的最左节点是5,节点5作为替换节点,没有左子节点和右子节点,节点5是黑色,进行调整操作,调用fixAfterDeletion方法,调整红黑树结构。

删除节点9,如下图

image
节点9没有右节点的最左子节点,那么就取左节点的最右子节点了,节点8刚好是黑色的,进行调整操作,调用fixAfterDeletion方法,调整红黑树结构。

  删除节点1,如下图

image
节点1没有左右子节点,且刚好是红色的,直接删除了。

总结下删除的3种情况:

  1. 待删除节点没有子节点,直接删掉。
  2. 待删除节点只有一个子节点,直接删除。
    1. 待删除的子节点是黑色,子节点修改成黑色。
    2. 待删除的子节点是红色,直接删除。
  3. 待删除节点有2个子节点
    1. 找出替换节点,优先寻找待删除节点的右子节点的最左子节点,找不到的话,就左子节点的最右子节点。
    2. 调整待删除节点的父节点和替换节点的关系。
    3. 调整替换节点的子节点和被删除节点子节点的关系。

总结

TreeMap由红黑树结构来实现的,以key-value存在。key不允许为空,value允许为空,key重复会覆盖,value可以重复,有序,非线程安全。

posted @ 2018-04-14 16:01  Ch1nYK  阅读(156)  评论(0编辑  收藏  举报