红黑树之左旋右旋与插入

红黑树:自平衡二叉查找树

性质1. 节点是红色或黑色。

性质2. 根节点是黑色。

性质3 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

 

旋转

左旋:

private void rotateLeft(Entry<K,V> p) {

        if (p != null) {                       // 判断旋转节点 p(如图的A) 是否为空

            Entry<K,V> r = p.right;       // 新建 r 变量为 p 的右孩子(如图的C)

            p.right = r.left;                 // 设置旋转节点 p(A)的新右孩子为旧右孩子(C)的右孩子(C2)

            if (r.left != null)                // 判断 C1 是否为空

                r.left.parent = p;              // 设置C1的父亲为旋转节点 p(A)

            r.parent = p.parent;            // 设置 C 的父亲为A的父亲

            if (p.parent == null)             // 判断旋转节点的父亲是否为空

                root = r;                        //        如果旋转节点的父亲为空,设置红黑树的根节点为 C

            else if (p.parent.left == p)     //如果旋转节点的父亲不为空

                p.parent.left = r;            //  1.旋转节点为其父亲的左孩子,设置新的左孩子为C

            else                               //   2.旋转节点为其父亲的右孩子,设置新的右孩子为C

                p.parent.right = r;       

            r.left = p;                       // 设置C的新左孩子为旋转节点(A)

            p.parent = r;                   // 设置旋转节点的父亲为 C

        }

    }

 

 

右旋:(同理如上)

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;

        }

    }

 

情况一

情况二

情况三

//插入-----树如何保持平衡
//根据 Comparator(默认<左小右大>或自定义 Comparator )
//插入完成后调用 fixAfterInsertion 方法:
private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED; // 默认插入的新节点为红色

        while (x != null && x != root && x.parent.color == RED) {       // 1.如果父亲节点为黑色不进行平衡
            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 (爷爷节点的父亲节点为黑色,调整结束)
                    x = parentOf(parentOf(x));                             
                } else {
                    if (x == rightOf(parentOf(x))) {   // 第二种情况(这情况必定是叔叔节点为黑色,可能第一种情况得出):
                        x = parentOf(x);               // 将调整节点 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;
    }

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值