红黑树插入修正和删除修正详解

红黑树概念请戳:点击打开链接-http://www.sohu.com/a/201923614_466939

红黑树代码请戳:点击打开链接-https://www.cnblogs.com/skywang12345/p/3624343.html

-------------------------------------------------------------------------------------------------

感觉他写的代码注释不是很详细,而且没有配图说明,有些看着很晕

所以这里对于<天王的博客>中红黑树插入修正和删除修正的代码这块进行详解

-------------------------------------------------------------------------------------------------

(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。

(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

---------------------红黑树:5大规则---------------------------------------------------------------------

首先,进行插入修正这块进行详解:


不需要调整的情况:


需要调整的情况:(因为插入节点是 红色节点 ,所以需要调整的都是违反 规则4 的)

GP-grandparent-祖父节点

P-parent-父节点

U-uncle-树节点

node-插入节点





-----------------------------------------------------------------------------------------------------

首先:对于case 1,进行调整分析




Case 1 达到平衡.............................................

--------------------------------------------------------------------------------------------------------------------------------

Case 2 分析:



这里处理方式是,将Case 2 转成 Case 3 然后一起处理!!!---------------------然后达到平衡

----------------------------------------------------------------------------------------------------------------------------------

Case 3 分析:



--------------------------------------------------------------------------------------------------------------------------------

Case 4 分析:




----------------------------------------------------------------------------------------------------------------------------------

Case 5 分析:



解决方式,就是将Case  5 转成 Case 6 然后一起解决.......................

---------------------------------------------------------------------------------------------------------------------------------

Case 6 分析:



--------------------------------------------------------------------------------------------------------------------------------

以上就是 插入的6种需要调整的情况,以及如何决定,和代码分析,极其详解

我的代码---用的<点击打开链接>这个大神的写的,然后根据自己想法写的,稍稍有点不一样,但大致是一样的

public void insertFixUp(RBNode<T> node) {
        RBNode<T> parent, gparent;

        while ((parent = node.parent) != null && parent.color == RED) {// 判断 是否 有父节点并且父节点为红色
            gparent = parent.parent;

            // * 插入节点前,该树是红黑树
            // * -父节点存在,且父节点为红色,那么父节点不是根节点(规则:根节点为黑色)
            // * -所以一定有祖父节点,且祖父节点为黑色(规则:父子节点不能同时为红色)
            // * -所以叔叔节点要么为黑色空节点,要么为红色节点(规则:从任意节点,到叶子节点上的黑色节点数相同(叶子节点指黑空节点))
            if (parent == gparent.leftChild) {
                /*
                 * 父节点是祖父节点的左孩子 叔叔节点是祖父节点的右孩子
                 */
                RBNode<T> uncle = gparent.rightChild;
                /*
                 * case 1:叔叔节点存在且为红色节点
                 */
                if (uncle != null && uncle.color == RED) {
                    uncle.color = BLACK; // 叔叔节点颜色调整为黑色
                    parent.color = BLACK;// 父节点颜色调整为黑色
                    gparent.color = RED;// 将祖父节点颜色调整为红色
                    node = gparent;// 在将祖父节点代入,判断祖父节点和祖父节点的父节点是否冲突
                    continue;// 继续循环
                }

                /*
                 * case 2:叔叔节点是黑空节点,且当前节点是父节点的右孩子
                 */
                if (parent.rightChild == node) {
                    leftRotate(parent); // 将父节点 左旋,当前节点 移动到父节点的位置,父节点移动到,当前节点的左孩子位置
                    RBNode<T> temp = parent;
                    parent = node;// 父节点 与 当前节点交换位置
                    node = temp;
                }

                /*
                 * case 3:叔叔节点是黑空节点,且当前节点是左孩子
                 */
                parent.color = BLACK;// 将父节点置为黑色
                gparent.color = RED;// 将祖父节点置为红色
                rightRotate(gparent);// 右旋祖父节点,达到平衡
            } else {

                // * 插入节点前,该树是红黑树
                // * -父节点存在,且父节点为红色,那么父节点不是根节点(规则:根节点为黑色)
                // * -所以一定有祖父节点,且祖父节点为黑色(规则:父子节点不能同时为红色)
                // * -所以叔叔节点要么为黑色空节点,要么为红色节点(规则:从任意节点,到叶子节点上的黑色节点数相同(叶子节点指黑空节点))

                // 父节点是祖父节点的右孩子
                RBNode<T> uncle = gparent.leftChild;

                /*
                 * case 4:叔叔节点存在且为红色节点
                 */
                if (uncle != null && uncle.color == RED) {
                    uncle.color = BLACK;
                    parent.color = BLACK;
                    gparent.color = RED;
                    node = gparent;
                    continue;
                }

                /*
                 * case 5:叔叔节点为黑色空节点,且当前节点为左孩子
                 */
                if (parent.leftChild == node) {
                    rightRotate(parent);
                    RBNode<T> temp = parent;
                    parent = node;// 父节点 与 当前节点交换位置
                    node = temp;
                }
                /*
                 * case 6:叔叔节点为黑色空节点,且当前节点为右孩子
                 */
                parent.color = BLACK;
                gparent.color = RED;
                leftRotate(gparent);
            }
        }

        root.color = BLACK;// 将根节点设置为黑色
    }

----------------------------------------------------------------------------------------------------------------------------------

插入修正画图就花了我一上午的时间弄的,自己用画图软件,一点一点画的.......贼辛苦

-----------------------------------------------------------------------------------------------------------------------------

接下来就是删除修正,这个是最麻烦的,光是理解代码意思,就花了我2天时间,画图就花了整整一个下午啊!!!!!

---而且还发现了代码的一处小瑕疵,还没验证对不对,但从图上理解,可以更简化点滴~

首先,朋友!删除节点,替代节点,了解一下........


-----------------------我这只是对修正进行了详解,如何删除,大家去看大神的代码,很详细了!!!


-------首先,我们调整结构时,需要用递归的思想去设计,就是先将冲突点的小部分结构调整过来,然后再定位到冲突点,再调整....

-------直至最后没有冲突为止(再调整冲突过程中,[规则5],和调整前要保持一致,这样就不需要,再为了黑色节点数目,去改变了!)


-----------------------------------------------------------------------------------------------------------------------------

就分为两大种情况了:

1.当node节点为红色时




代码:

so Easy........

----------------------------------------------------------------------------------------------------------------------------------

第二大种:

就是当node节点为黑空节点时:

Case 1 分析:





这种处理,就是Case 1 转成 Case 2 或 Case 3,4,5,然后一起处理.........


最后再将node节点置为黑色!!!

----------------------------------------------------------------------------------------------------------------------------------

Case 2 分析:




Case 2,就是将兄弟节点,置为红色,就解决了,然后在将node节点,置为parent节点,然后,再进行循环判断,是否冲突,如果不冲突就跳出循环

---------------------------------------------------------------------------------------------------------------------------------

Case 3分析:



----这个节点颜色,和一开始就没啥区别呀.....而且要变成黑色,也可以到最后变成兄弟节点右孩子时,再置黑一样的.....

----大家可以看看,先将兄弟节点置红,然后右旋,再将兄弟节点置为父节点的右孩子,然后再将兄弟节点的右孩子置黑

----感觉可以不置红,直接后面兄弟节点的右孩子置黑,就行了,所以这步应该可以省略的.....


---------------------------------------------------------------------------------------------------------------------------------

Case 4 分析:




----------------------------------------------------------------------------------------------------------------------------------

Case 5 分析:




可以看到 Case 4 和 Case 5,在操作上基本没啥区别,就是兄弟节点的右孩子为红色时,左孩子不管是红还是黑都没影响

----------------------------------------------------------------------------------------------------------------------------------


下半部分代码,基本就是上面分析的情况,将兄弟节点 和 node节点 对调过来,再分析就行了

----------------------------------------------------------------------------------------------------------------------------------

代码也是---我自己加了点注释,基本一样,就是中间,有句代码,有点多余,但不影响

    // node待修正的节点
    public void removeFixUp(RBNode<T> node, RBNode<T> parent) {
        RBNode<T> other;

        // 1.node = null 不是 root节点 进入循环
        // 2.node != null,node.color = black,不是 root节点 进入循环
        while ((node == null || node.color == BLACK) && node != root) {
            // 待修正节点 为 父节点的 左孩子节点
            if (parent.leftChild == node) {
                other = parent.rightChild;
                // 父节点 的 右子节点
                if (other.color == RED) {
                    // case 1: node 的 兄弟节点 是红色
                    other.color = BLACK;
                    parent.color = RED;
                    leftRotate(parent);
                    other = parent.rightChild;
                }

                if ((other.leftChild == null || other.leftChild.color == BLACK)
                        && (other.rightChild == null || other.rightChild.color == BLACK)) {

                    // Case 2 :1.兄弟节点 左孩子为空 并且 右孩子为空,2.兄弟节点 左孩子为黑色 并且 右孩子为黑色
                    other.color = RED;
                    node = parent;
                    parent = node.parent;
                } else {

                    if (other.rightChild == null || other.rightChild.color == BLACK) {
                        // Case 3 :兄弟节点,右孩子为空或为黑色
                        other.leftChild.color = BLACK;
                        other.color = RED;//这步可省略
                        rightRotate(other);
                        other = parent.rightChild;
                    }

                    // Case 4 :兄弟节点,右孩子为红色,左孩子为黑色
                    // Case 5 :兄弟节点,右孩子为红色,左孩子为红色
                    other.color = parent.color;
                    parent.color = BLACK;
                    other.rightChild.color = BLACK;
                    leftRotate(parent);
                    node = this.root;
                    break;
                }
            } else {

                other = parent.leftChild;
                if (other.color == RED) {
                    // Case 1: 兄弟节点为红色
                    other.color = BLACK;
                    parent.color = RED;
                    rightRotate(parent);
                    other = parent.leftChild;
                }

                if ((other.leftChild == null || other.leftChild.color == BLACK)
                        && (other.rightChild == null || other.rightChild.color == BLACK)) {

                    // Case 2:兄弟节点是黑色,且两孩子也是黑色
                    other.color = RED;
                    node = parent;
                    parent = node.parent;
                } else {
                    if (other.leftChild == null || other.leftChild.color == BLACK) {
                        // Case 3:兄弟节点是黑色,且左孩子是红色,右孩子为黑色
                        other.rightChild.color = BLACK;
                        other.color = RED;
                        leftRotate(other);
                        other = parent.leftChild;
                    }

                    // case 4:兄弟节点是黑色,兄弟节点的右孩子是红色,左孩子任意
                    other.color = parent.color;
                    parent.color = BLACK;
                    other.leftChild.color = BLACK;
                    rightRotate(parent);
                    node = this.root;
                    break;
                }
            }

        }

        if (node != null) {
            node.color = BLACK;
        }
    }

----------------------------------------------------------------------------------------------------------------------------------

以上基本就是,红黑树,最经典的插入修正和删除修正的图,以及代码分析!!!

感叹一句,发明红黑树5条规则的人,真TN是个人才!!!!!

----------------------------------------------------------------------------------------------------------------------------------

理解代码到画图基本花了3-4天时间........佩服我自己!!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值