TreeMap底层红黑树源码浅析

分析java集合的时候,HashMap的存储优化和TreeMap的底层都使用到了红黑树
来看一看红黑树调整的具体源码。
版本:jdk1.8
    //首先是一个Entry类(TreeMap的内部类)
    //包含,key、value、左孩子引用、右孩子引用、父节点引用、结点颜色(默认为黑色结点)
    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;
        }
        //重写了equals、hashcode、toString方法
        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;
        }
    }
    //TreeMap内的方法
    /**
    关键就是理解左旋与右旋的方式与染色,结点指向的改变等,代码参考图示就可理解
    **/
    //左旋
    private void rotateLeft(Entry<K,V> p) {
        if (p != null) {
            Entry<K,V> r = p.right;//p的右节点
            p.right = r.left;//让p的右结点指向原来r的左节点
            if (r.left != null)//不等于null要设置parent
                r.left.parent = p;
            r.parent = p.parent;//更改父指针
            if (p.parent == null)
                root = r;//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;
        }
    }

    //插入后调整
    private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED;//新插入的结点颜色置为红色
        while (x != null && x != root && x.parent.color == RED) {//父节点为红色
            //若x的父节点==x的爷结点的左节点(也就是L)
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                //找到叔叔结点
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {//如果是红色
                    setColor(parentOf(x), BLACK);//父染色
                    setColor(y, BLACK);//叔染色
                    setColor(parentOf(parentOf(x)), RED);//爷染色
                    x = parentOf(parentOf(x));//将爷结点看作新结点
                } else {
                    //否则,叔为黑色,需要旋转调整
                    //如果子结点为父节点的右节点(连着上面,也就是LR)
                    if (x == rightOf(parentOf(x))) {
                        x = parentOf(x);//此时x为插入结点的父节点
                        rotateLeft(x);//先左旋
                    }
                    //子结点为父节点的左节点(连着上面,也就是LL)
                    //当然,上面的执行完上面的LR中的if,也要执行下面。
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));//右旋
                }
            } else {
                //父为R
                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))) {//RL
                        x = parentOf(x);
                        rotateRight(x);//右旋
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));//左旋
                }
            }
        }
        root.color = BLACK;
    }

红黑树的调整:

NOTE:叔叔为父节点的兄弟结点,我们将空域也看作一个结点,爷结点为父节点的父节点。
1、插入的为根节点,直接染黑
2、否则染为红色,插入
若破坏了红黑树的特性,需要染色
    - 若叔叔结点为红色
      - 叔结点,父节点,爷结点染色(都变为与原来相反的颜色)---->爷结点变为新结点(也就是把爷结点当作新插入的结点),重复上述步骤
    - 若叔叔结点为黑色
      - LL旋转,旋转完,将父和爷染色【以父结点为旋转中心】
      - RR旋转,------------------
      - LR旋转,旋转完,将新节点与爷结点染色【先以父结点为旋转中心,再以新结点为旋转中心】
      - RL旋转,-------------------------

调整过程图示:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值