红黑树相关问题

红黑树的五大性质

1、节点都有颜色,不是黑色就是红色
2、null表示黑色(叶子节点的left和right地址域)
3、根节点是黑色
4、不能出现连续的红色节点
5、从根节点到任意叶子节点的路径上的黑色节点数量是相同的

根据红黑树的性质可以得出:节点左右子树的高度差,高子树的高度不超过低子树的高度的2倍

为了维护红黑树的五大性质,所做的操作有:
1、左旋转
2、右旋转
3、节点着色

红黑树的插入操作(insert):

注意:以下情况均以新插入节点的父节点是祖先节点的左孩子的情况下进行的
1、第一次插入的是根节点,那么就直接涂成黑色(对应性质3)
2、在红黑树不空的情况下,进行节点的插,那么新插入的节点都为红色(对应性质5,因为如果新插入的节点是黑色的,那么当前插入的节点就会使当前这一路径上黑色节点的数量增加,从而违背了性质5)

检查操作:
1、:如果父节点是黑色的,那么就直接插入,不用做任何调整
2、:如果父节点是红色的,那么此时就不满足红黑树的性质4,需要进行插入调整操作,有以下情况:
①:当新插入的节点为其父节点的左孩子,并且其叔叔节点为黑色时,将父节点与祖先节点的颜色互换,然后再以祖先节点为根节点进行又旋转,操作完成。
在这里插入图片描述
②:当新插入节点为其父节点的右孩子,并且其叔叔节点为黑色时,先以父节点为根节点进行左旋转操作,此时转变为情况①,再按情况①的方法进行处理,操作完成
在这里插入图片描述
③:当叔叔节点不再是黑色,而是红色的时候,需要将叔叔节点与父节点都涂成黑色,并且将祖先节点涂成红色,再把祖先节点当作新节点,继续按以上步骤进行检查
在这里插入图片描述
红黑树的插入调整代码如下:

public void fixAfterInsert(Entry<T> node){
        while(color(parent(node)) == Color.RED){

            //表示新插入节点在其祖先节点的左侧
            if(left(parent(parent(node))) == parent(node)){
                Entry<T> uncle = right(parent(parent(node)));

                //情况3:当叔叔的颜色也是红色时
                if(color(uncle) == Color.RED){

                    //将父亲与叔叔的颜色都涂成黑色
                    setColor(parent(node),Color.BLACK);
                    setColor(uncle,Color.BLACK);

                    //由于当前这两条路径多出了两个黑色,所以要将父亲与叔叔共同的父亲,也就是祖先节点涂成红色
                    setColor(parent(parent(node)),Color.RED);
                    /**
                     * 由于现在祖先节点被涂成了红色,如果祖先节点的父节点也是红色,
                     * 那么就不满足红黑树的性质了(即不能出现连续的红色节点),所
                     * 以需要将node指向祖先节点,进入循环继续向上检查
                     */
                    node = parent(parent(node));
                }else{

                    //处理新插入节点再其父节点的右侧的情况,后续步骤下面统一处理
                    if(right(parent(node)) == node) {
                        node = parent(node);
                        leftRotate(node);
                    }

                    //当新插入节点在其父节点的左侧时,交换父节点与祖先节点的颜色
//                    Color c = color(parent(parent(node)));
//                    setColor(parent(parent(node)),color(parent(node)));
//                    setColor(parent(node),c);
                    ColorExchange(parent(parent(node)),parent(node));
                    //再以祖先节点为根节点进行右旋转
                    rightRotate(parent(parent(node)));
                    break;
                }
            }else{
                //新插入的节点在其祖先节点的右侧
                Entry<T> uncle = left(parent(parent(node)));
                if(color(uncle) == Color.RED){
                    setColor(uncle,Color.BLACK);
                    setColor(parent(node),Color.BLACK);
                    setColor(parent(parent(node)),Color.RED);
                    node = parent(parent(node));
                }else{
                    if(left(parent(node)) == node){
                        node = parent(node);
                        rightRotate(node);
                    }
                    ColorExchange(parent(parent(node)),parent(node));
                    leftRotate(parent(parent(node)));
                    break;
                }
            }
        }
        //由于以上调整可能会使根节点的颜色发生改变,所以再调整完成后,需要重新将根节点涂成黑色
        setColor(this.root,Color.BLACK);
    }

红黑树的删除操作操作:

注意:
以下情况均指待删除节点(node)是其父节点的左孩子,另一种情况方法与之相同,操作方向发生改变
如果删除的节点是红色节点,删除完成后直接结束;如果删除的节点是黑色节点,那么就破坏了红黑树的性质5,需要进行删除调整操作
当黑色节点被删除后,需要将这个被删的黑色节点的孩子补上来,当补上来的这个孩子节点的颜色是:

1、红色,那就直接将补上来的这个孩子节点涂成黑色就完成了

2、黑色,且再自己这一条路径没法补充一个黑色节点了,这时就需要从它的兄弟节点借一个黑色节点过来,情况如下:

①:当待删除节点的兄弟节点是黑色,兄弟节点的右孩子是红色时,将父节点与兄弟节点的颜色交换,再将兄弟节点的右孩子涂成黑色,最后以父节点为根节点进行左旋转,操作完成

②:当待删除节点的兄弟节点是黑色,但是兄弟节点的右孩子不是红色时,兄弟节点与其左孩子节点颜色交换,再以兄弟节点为根节点进行右旋转,此时待删除节点的兄弟节点改变,需要重新设置兄弟节点,设置完成后变为情况①,按①中方法进行处理

③:当待删除节点的兄弟节点是黑色,且兄弟节点的左右孩子都是黑色时,将兄弟节点涂成红色,node指向父节点,父节点如果是红色,直接跳出循环,并将父节点涂成黑色,如果父节点本来就是黑色,则继续向上检查

④:当待删除节点的兄弟节点是红色时,交换兄弟节点与父节点的颜色,并以父节点为根节点进行左旋转操作,此时,待删除节点的兄弟节点发生改变,需要更新兄弟节点,更新后的兄弟节点一定变为了黑色(因为更新前兄弟节点是红色的,其左右孩子一定为黑色,而这些黑色节点在旋转后就变成了待删除节点的新兄弟节点),此时就可以按①②③步骤处理

红黑树与AVL树的比较:

是否是平衡树:AVL是自平衡的二叉搜索树,红黑树不是自平衡的二叉搜索树

insert方法比较:AVL最多旋转两次,红黑树也是最多旋转两次,但是还涉及到节点着色的问题

remove方法比较:AVL最多为logn次(取决于树的高度),而红黑树最多旋转3次,并涉及节点着色

query方法比较:两种二叉搜索树的时间复杂度都是O(logn),但由于AVL是自平衡的二叉搜索树,所以AVL在查询效率上更高

使用场景建议:当查询、插入操作比较多的时候推荐使用AVL,而当插入、删除、查询操作都多的时候,推荐使用红黑树

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值