二叉树之红黑树的删除方法(JAVA代码实现)

上一章写到了红黑树的插入,今天记录下红黑树的删除方法,因为删除方法比插入更麻烦,情况更多,顾单独写一章。
有关红黑树的插入请看我这篇博客:https://blog.csdn.net/CSDN_LICY/article/details/104806459
有关AVL的插入与删除请看这篇博客:https://blog.csdn.net/CSDN_LICY/article/details/104735594

一、删除的几种情况

假设删除节点为D,一下均是D在左子树的分析情况,D在右子树,均是镜面对称操作。
在这里插入图片描述

二、删除代码

public void remove(int element) {
    removeForBalance(element, root, true);
    deleteElement(element, root);
}
public void removeForBalance(int element, RedBlackNode redBlackNode, boolean isRemove) {
    if (redBlackNode == null) {
        return;
    }
    if (element == root.element && root.left == null && root.right == null) {
        root = null;
        return;
    }
    int compareResult = element - redBlackNode.element;
    if (compareResult < 0) {
        removeForBalance(element, redBlackNode.left, isRemove);
    } else if (compareResult > 0) {
        removeForBalance(element, redBlackNode.right, isRemove);
    } else if (redBlackNode.left != null && redBlackNode.right != null && isRemove) {
        //当要删除的节点左右节点都不为空,则找到他的直接后继节点,来替换当前节点,最后再删除后继节点
        redBlackNode.element = findMin(redBlackNode.right).element;
        removeForBalance(redBlackNode.element, redBlackNode.right, isRemove);
    } else {
        parent = redBlackNode.parent;
        //已经找到需要删除的节点,接下来进行删除,并恢复红黑树,假设待删除节点为D
        //D为红节点只有一种情况;D为红节点,并且D为叶子节点
        if (getColor(redBlackNode) == RED && redBlackNode.left == null && redBlackNode.right == null) {
            return;
        }
        //D为黑节点,分为两种:1、D左节点或右节点为空,此时另一个节点必然为红节点。2、D为叶子节点
        if (redBlackNode.left != null && isRemove) {
            redBlackNode.element = redBlackNode.left.element;
            redBlackNode.left = null;
            return;
        }
        if (redBlackNode.right != null && isRemove) {
            redBlackNode.element = redBlackNode.right.element;
            redBlackNode.right = null;
            return;
        }
        //下面讨论最复杂的情况:D为叶子节点,(每种情况都包含镜面对称情况)
        if (redBlackNode.parent == null) {
            redBlackNode.color = BLACK;
            return;
        }
        if (redBlackNode == redBlackNode.parent.left) {
            brother = parent.right;
            if (getColor(brother) == RED) {
                //第一种情况
                removeByBrotherIsRed(true);
                removeForBalance(redBlackNode.element, root, isRemove);
            } else if (getColor(brother) == BLACK && getColor(brother.right) == RED) {
                //第二种情况
                removeByRemoteBrotherSon(true);
            } else if (getColor(brother) == BLACK && getColor(brother.left) == RED) {
                //第三种情况
                removeByCloseBrotherSon(true);
            } else if (getColor(parent) == RED && getColor(brother) == BLACK && getColor(brother.left) == BLACK && getColor(brother.right) == BLACK) {
                if (brother.left == null && brother.right == null) {
                    //第四种情况
                    //父节点为红色,兄弟节点和两个侄子节点都是黑色,且两个侄子为空
                    parent.color = BLACK;
                    brother.color = RED;
                } else if (brother.left != null && brother.right != null) {
                    //第五种情况
                    //父节点为红色,兄弟节点和两个侄子节点都是黑色,且两个侄子不为空
                    //父节点左单旋
                    leftRotate(parent);
                }
            } else if (getColor(parent) == BLACK && getColor(brother) == BLACK && getColor(brother.left) == BLACK && getColor(brother.right) == BLACK) {
                //第六种情况
                brother.color = RED;
                removeForBalance(parent.element, root, false);
            }
        }
        if (redBlackNode == redBlackNode.parent.right) {
            brother = parent.left;
            if (getColor(brother) == RED) {
                //第一种情况 的镜面对称情况
                removeByBrotherIsRed(false);
                removeForBalance(redBlackNode.element, root, isRemove);
            } else if (getColor(brother) == BLACK && getColor(brother.left) == RED) {
                //第二种情况 的镜面对称情况
                removeByRemoteBrotherSon(false);
            } else if (getColor(brother) == BLACK && getColor(brother.right) == RED) {
                //第三种情况 的镜面对称情况
                removeByCloseBrotherSon(false);
            } else if (getColor(parent) == RED && getColor(brother) == BLACK && getColor(brother.left) == BLACK && getColor(brother.right) == BLACK) {
                if (brother.left == null && brother.right == null) {
                    //第四种情况 的镜面对称情况
                    //父节点为红色,兄弟节点和两个侄子节点都是黑色,且两个侄子为空
                    parent.color = BLACK;
                    brother.color = RED;
                } else if (brother.left != null && brother.right != null) {
                    //第五种情况 的镜面对称情况
                    //父节点为红色,兄弟节点和两个侄子节点都是黑色,且两个侄子不为空
                    //父节点右单旋
                    rightRotate(parent);
                }
            } else if (getColor(parent) == BLACK && getColor(brother) == BLACK && getColor(brother.left) == BLACK && getColor(brother.right) == BLACK) {
                //第六种情况
                brother.color = RED;
                removeForBalance(parent.element, root, false);
            }
        }
    }
    return;
}
/**
 * 第一种情况:D的兄弟节点为红色。
 * 思路:父节点和兄弟节点颜色互换,并且以父节点为当前节点进行旋转,变成情况四
 * 当祖父节点存在,则让祖父节点指向新的父节点,否则,旋转后的节点为root。
 * 此情况存在镜面对称情况,用isLeft区分,
 * 当前节点是父节点的左节点,则isLeft为true,进行左单旋,否则进行右单旋。
 *
 * @param isLeft
 */
private void removeByBrotherIsRed(boolean isLeft) {
    int parentColor = getColor(parent);
    parent.color = getColor(brother);
    brother.color = parentColor;
    if (parent.parent != null) {
        grand = parent.parent;
        if (grand.left == parent) {
            grand.left = isLeft ? leftRotate(parent) : rightRotate(parent);
        } else {
            grand.right = isLeft ? leftRotate(parent) : rightRotate(parent);
        }
    } else {
        root = isLeft ? leftRotate(parent) : rightRotate(parent);
    }
}

/**
 * 第二种情况:D的远侄子为红色
 * 思路,删除后右子树比左子树多一个黑节点,想办法让红节点变成黑节点,并让右子树两个黑节点分布到两个子树
 * 1、父节点和兄弟节点互换颜色
 * 2、远侄子变成黑色
 * 3、对父节点进行RR操作(左单旋)
 * isLeft为false则就是镜面对称情况,进行右单旋
 * @param isLeft
 */
private void removeByRemoteBrotherSon(boolean isLeft) {
    int parentColor = parent.color;
    parent.color = brother.color;
    brother.color = parentColor;
    if (isLeft) {
        //parent.left = null; //删除D
        brother.right.color = BLACK;
    } else {
        //parent.right = null; //删除D
        brother.left.color = BLACK;
    }
    if (parent.parent != null) {
        grand = parent.parent;
        if (grand.left == parent) {
            grand.left = isLeft ? leftRotate(parent) : rightRotate(parent);
        } else {
            grand.right = isLeft ? leftRotate(parent) : rightRotate(parent);
        }
    } else {
        root = isLeft ? leftRotate(parent) : rightRotate(parent);
    }
}

/**
 * 第三种情况:D的近侄子为红色
 * 1、将兄弟节点和近侄子颜色互换
 * 2、将兄弟节点右单旋,(此时兄弟节点和侄子角色互换)然后就变成了第二种情况
 * 3、按照第二种情况进行删除
 * isLeft为false则就是镜面对称情况,进行左单旋
 * @param isLeft
 */
private void removeByCloseBrotherSon(boolean isLeft) {
    int brotherColor = getColor(brother);
    brother.color = getColor(brother.left);
    if (isLeft) {
        brother.left.color = brotherColor;
    } else {
        brother.right.color = brotherColor;
    }
    if (isLeft) {
        parent.right = rightRotate(brother);
        brother = parent.right;
    } else {
        parent.left = leftRotate(brother);
        brother = parent.left;
    }
    removeByRemoteBrotherSon(isLeft);
}

private void deleteElement(int element, RedBlackNode redBlackNode) {
    if (redBlackNode == null) {
        return;
    }
    if (element == root.element && root.left == null && root.right == null) {
        root = null;
        return;
    }
    int compareResult = element - redBlackNode.element;
    if (compareResult < 0) {
        deleteElement(element, redBlackNode.left);
    } else if (compareResult > 0) {
        deleteElement(element, redBlackNode.right);
    } else {
        //找到删除节点直接删除
        parent = redBlackNode.parent;
        if (redBlackNode == parent.left) {
            parent.left = null;
        } else {
            parent.right = null;
        }
    }
}

/**
 * 找到最小节点
 * @param redBlackNode
 * @return
 */
private RedBlackNode findMin(RedBlackNode redBlackNode) {
    if (redBlackNode == null) {
        return null;
    } else if (redBlackNode.left == null) {
        return redBlackNode;
    }
    return findMin(redBlackNode.left);
}

三、测试结果

在这里插入图片描述

后记

关于二叉树的知识暂时就分享到这。
总的来说,自己收获很大,之前一直没搞懂红黑树,借此机会,也算是对自己一个交代。尤其对jdk8给hashMap增加红黑树有了更深的理解。

项目源码:
github:https://github.com/licy-IT/Tree.git
码云:https://gitee.com/rising-dragon/Tree.git

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值