数据结构-红黑树

红黑树的概述

二叉搜索树有一个很麻烦的问题,如果树中插入的是随机数据,执行效果会好,但是,如果插入的是有序数据,速度变得特别慢,因为此时二叉树是非平衡树,而对于非平衡树,它的快速查找数据能力就会丧失。如下图
在这里插入图片描述
红黑树是增加了某些特点的二叉搜索树,它保证了树的平衡,在红黑树中搜索方法和二叉树一样
红黑树的平衡是在插入的过程中取得的,对于一个要插入的数据项,插入过程要检查不会破坏树一定的特征,如果此过程破坏了,程序就会进行纠正

红黑树的两个特征:
  • 节点都有颜色,每个节点不是黑色就是红色
  • 在插入和删除的过程中,要遵循保持这些颜色的不同排列的规则
红黑树保证树平衡的规则
  • 每个节点不是红色就是黑色
  • 根节点总是黑色的
  • 如果节点为红色,则它的子节点必须时黑色(反过来则不一定)
  • 从根节点到叶子节点或空子节点每条路径,必须包括相同数目的黑色节点
  • 新插入的节点总是红色(除了根节点)
红黑树如何解决违规的情况
  • 改变节点的颜色,包括从黑色到红色,也包括从红色到黑色
  • 执行旋转操作,是值重新排列节点,使树更趋于平衡,分为右旋和左旋两种旋转
旋转操作分为左旋和右旋

选择一个节点,作为旋转的顶端,如下图(顶端节点为50):
在这里插入图片描述

在这里插入图片描述
注意:
如果是右旋,顶端节点必须有一个左子节点,否则,将会出现没有节点旋转到顶端节点原来的位置,类似的,如果执行左旋,顶端节点必须有一个右子节点
横向移动节点
红黑树在旋转的过程中,可能会出现节点无法继续挂在父节点的情况,此时需要进行横向移动操作,如下图(旋转顶端为:50):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

当以50为顶点向右旋转之后,25节点会移动到50节点原来的位置,50节点称为25节点的新右子节点,13节点继续作为25的左子节点上移,此时,25节点的原右子节点38则会出现无处可挂的情况
我们此时仔细观察旋转之后的结果,原来50节点的左节点是25节点,右子节点是75。当发生右旋之后,50节点成为了25节点的右子节点,而75节点依然是50节点的右子节点,并且位置下移,但是因为25节点变成了50节点的父节点所以50节点的左子节点一定为空,此时。我们将38节点向右横向移动,成为50节点的左子节点。对于38节点的行为,我们称之为"横向移动"
那么38节点能不能成为13的右子节点呢?答案是不能,我们上图中13是没有右子节点,所以会有个错觉认为38可以成为13的右子节点,但13是有可能本来就有右子节点,所以说节点38不能挂在节点13的下面

所以可以理解为对内侧子孙节点而言,如果它是上移节点的子节点,它总是要断开和父节点的连接并重新连接到它以前的祖父节点上 我们上图的38就是内侧子孙节点,25是以前的父节点,50是以前的祖父节点,所以先断开和25的连接,然后连接到50即可

插入一个新节点

现在有了足够的红黑树的背景知识,我们可以开始学习红黑树的插入算法如何利用旋转和颜色规则来保持树的平衡

下行途中颜色变换

当顺着树向下查找新节点的插入位置时,只要发现一个黑色节点有两个红色的子节点时,必须把它子节点变为黑色,并且把父节点变为红色(根节点除外,根必须是黑色),如下图:
在这里插入图片描述
在这里插入图片描述
好处

  • 黑色高度不改变
  • 叶子节点从红色变成了黑色,更容易连接新节点,因为新节点必须是红色的
新节点插入后的位置定义

根据新节点X插入之后所在的位置不同,我们可以定义为不同的名字,如下图(X表示新插入的节点)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 如果节点在父节点的一侧与父节点在祖父节点一侧相同,则节点就是一个外侧子孙节点(可以理解为新插入的节点在父节点的左子节点而父节点又在祖父节点左子节点没有变向这样就是外侧子孙节点,反之右子节点也一样)
  2. 相反,如果节点在父的一侧,而父在祖父的另一侧,则节点就是一个内侧子孙节点(可以理解为右转向就是内侧子孙节点)
插入节点之后的旋转

新节点的插入可能会违背红黑树规则。因此,在插入新节点之后,必须要检查是否违背规则,并采取相应的措施,保证红黑树的正确
在下面的讨论中,使用X、P、G表示关联的节点。X表示违反规则的节点,P是X的父节点,G是P的父节点,也就是说G是X祖父节点。
注意
有时候X指的是新插入的节点,有时指的是父节点和子节点发生的红红冲突时的子节点。
下面,我们通过插入新节点之后的不同情况,来分析插入新节点后,红黑树需要进行的一系列操作

  1. 情况1:
    如果P是黑色的,就什么事情都不用做。刚刚插入的X节点总是红色的,没有违背任何规则,直接插入。如下图:
    在这里插入图片描述
    根据上图来看,插入新节点13后,没有发生红红冲突,也没有改变黑色节点高度,所以没有任何问题,直接插入
  2. 情况2:
    在情况1的基础上,我们继续插入一个新节点7,此时,X节点指的是新节点7,不再是节点13
    X是一个外侧子孙节点,P是红色的,则需要进行一次旋转和一次颜色的改变,如下图展示的变色和旋转过程:
    在这里插入图片描述
    上图已经出现了红红冲突的情况违反了我们之前说的规则中的第三条(如果节点为红色,则它的子节点必须是黑色)所以这里我们需要进行一次变色,如下图:
    在这里插入图片描述
    上图是使用变色解决了红红冲突的问题
    在这里插入图片描述
    在这种情况下,采取三个步骤使树重新符合红黑树规则
    改变X的祖父节点G的颜色
    改变X的父节点P的颜色
    以X的祖父节点G为顶旋转,执行旋转操作,在本例中是执行右旋
  3. 情况3:
    如果P是红色的,X是内侧子孙节点,则需要两次旋转和一次变色的改变,请注意本情况与情况2中颜色变换的区别
    在这里插入图片描述
    在这里插入图片描述
    上图:可以看出本情况和情况二的变色不一样,本情况是插入节点X变色和X的祖父节点变色
    在这里插入图片描述
    在这里插入图片描述
    上图就是经过第一次旋转后的效果,可以看出已经变成了情况2变色之后的效果,之后我们好像情况2那样用G节点作为顶端节点向右旋转一次就可以了
    在这里插入图片描述
    在这种情况下,需要执行4步操作使树重新符合红黑树规则
    改变X的祖父节点的颜色
    改变X的颜色
    以X的父节点P为顶旋转,执行左旋
    以X的祖父节点G为顶旋转,进行右旋
    注意:
    情况3与情况2改变颜色的节点不同,并且旋转次数不同,情况3发生一次变色和一次旋转之后,样子和情况2第一次变色后是一样的(指的是样子,不是节点值)
  4. 情况4:在下行路途中的旋转
    在下行路途中查找插入点时所做的旋转 ,发生在节点插入之前,相比于为新插入的节点所作旋转更复杂,颜色改变和旋转次数更多,可能还包括节点横移的情况,在已知的红黑树中插入新的节点,如下图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    从上图我们可以看到和情况2同样的情况 X(12)节点是一个外侧子孙节点,P是红色的,所以我们接下来就进行一次旋转和一次颜色的改变
    注意:我们要变色的是P节点和G节点 G节点是根节点变色和会变成红色,根节点是不能变红色的,但因为我们还有一个旋转在后面旋转之后现在的根节点50就不再是根节点了,所以可以变成红色

在这里插入图片描述
然后就是以G(50节点作为顶端节点)进行一次向右旋转
在这里插入图片描述
旋转之后 我们可以看到,原来属于25节点的右子节点37无节点可挂
这个就是属于本文中一开始说的那种情况横向移动节点,所以现在可以横向37移动节点,成为原来的根节点50节点的左子节点
在这里插入图片描述
到最后我们可以发现,居然是一颗平衡树,其实,只是遵循颜色变换和旋转的结果,此时,我们继续在数组插入节点3,没有任何违规情况出现,顺利插入 如下图
在这里插入图片描述
以下再写一个例子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们按照情况三的第一个步骤进行变色
在这里插入图片描述
下图我们按照情况3按P节点作为顶端节点向左旋转
在这里插入图片描述

在这里插入图片描述
接下来我们进行第二次旋转,以G节点为顶端结对向右旋转
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
红黑树是一种自平衡的二叉查找树,它在插入和删除节点时能够保持树的平衡。红黑树的概念可以参考。在Java中实现红黑树,可以按照以下步骤进行: 1. 首先将红黑树当作一颗二叉查找树,将新节点插入到适当的位置上。 2. 将插入的节点着色为"红色"。 3. 根据红黑树的特性,通过一系列的旋转和着色等操作,使树重新保持红黑树的性质。 具体的插入过程可以参考中提供的代码。在代码中,使用了左旋转、右旋转和颜色翻转等操作来重新平衡红黑树。 首先,如果节点的右子树是红色而左子树是黑色,可以通过左旋转操作将其变为左子树为红色,右子树为黑色的情况。 其次,如果节点的左子树和左子树的左子树都是红色,可以通过右旋转操作将其修正为上述情况。 最后,如果节点的左子树和右子树都是红色,可以通过颜色翻转操作将其修正为左子树和右子树都为黑色的情况。 在插入完节点后,需要将根节点的颜色设置为黑色,以确保红黑树的性质满足。 这样,通过以上的步骤,就能够实现对红黑树的插入操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java数据结构红黑树的真正理解](https://download.csdn.net/download/weixin_38622475/12770272)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Java高阶数据结构红黑树](https://blog.csdn.net/qq15035899256/article/details/126678970)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java数据结构——红黑树](https://blog.csdn.net/weixin_30699463/article/details/95256212)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值