下面才是真正的红黑树主角登场:
在此之前先叠甲!有错欢迎友好指正,要是上来开喷就让你见识一下魔王S喷子的实力。别杠杠就是你对。
总概念:
首先都说红黑树了,那肯定是一种有红色和黑色的树嘛对吧(bushi)。不过有一说一确实红黑树在我的代码表示就是属于节点颜色要么是一个红色一个黑色的。同时,红黑树是属于平衡二叉树的一种。
心路历程一下:本来是在YouTube上面看教程的但是英语水平真的是一个大问题然后机器翻译也是十分的顶级,然后b站内部的教学也是一团糟所以就直接看优快云了。
参考思路:【数据结构】史上最好理解的红黑树讲解,让你彻底搞懂红黑树-优快云博客
其实人家讲的很详细了我就按照我自己的理解来总结一下的而已。。。
(其实我也就是学完之后再总结一次的,只是当作自己记录学习过程使用。)
好了言归正传。其实一切的操作都是根据性质执行的。
所以先介绍一下一些前置概念。
红黑树的基本性质:
- 根节点和表示空节点(这里看做为叶子结点,就是有一点不一样的。这里的空节点也是看成叶子结点的,后面都统一表示为叶子结点)一定是黑的。
- 普通的节点可以是红色的也可以是黑色的。
- 两个红色的节点不能相邻链接。
- 从任意节点到叶子节点路径上经过的黑色节点数量一样多。
然后就是一些基本概念了
- 父节点:就是父结点,一样的。
- 祖父节点:就是父结点的父结点。
- 叔节点:就是父结点的兄弟节点。祖父节点的另外一个儿子节点。
好的现在开始进入正题。
首先是红黑树形如这样:
但是可以变成
转变规则是红色的节点往上和黑色的父结点合并成一个新的节点。黑色的节点不动,等待红色节点的合并(如果有的话)。
这样子的四阶b树。(n阶b树就是表示一个节点最多存放n-1个数据)
然后这样子的b树节点的中间节点一定是要黑色的(表示父结点)。
然后就是左旋右旋之类的操作。RR,RL,LL,LR 之类的。
直接文字描述(言简意赅的偷懒)
假设1是祖父节点2是右父结点3是右子节点
RR就是调整的时候,把2变化为新的父结点,1,3分别变成左右子节点。(超级加辈)然后再接回去原来的树。
同理LL也是一样。
假设1是祖父节点,2是右父结点,3是左子节点。
RL就是调整的时候,把3变成新的父结点,1,2分别变成左右结点。
同理LR也是一样。
其实核心本质都是找到中间大小的结点然后作为新的子树的父结点,其他两边的点根据大小排在左右两边就可以了。具体视频推荐
一秒学会 平衡二叉树的调整,非标题党!不简单你打我! (考研数据结构)_哔哩哔哩_bilibili
都说了红黑树就是一种特殊的平衡二叉树,所以其实具体的红黑树调整方法也会用到以上的“旋转方法”。
那么肯定是插入和删除操作是最常用的对吧你哪怕初始化都是一种插入操作对吧,所以这里也是着重讲一下删除和插入操作。
插入操作:
情况一:根节点
那就很好啊直接使用形式这个就是黑的节点。
(除了情况一,一般情况下都是插入的红色节点,因为根据性质4,如果插入的是黑色的话需要额外的操作调整。也不是不行就是麻烦吧但是谁会没苦硬吃呢)
情况二:插入到黑色节点后面。
只要是满足上述性质的随便你怎么插入都行。不用额外操作。
情况三:插入在了红色的后面
例如这一种,假设我要插入52或者60。(这里的48和74是不存在的。)
先说52,那怎么办呢?这里我是把“两个红色节点不能相邻链接”作为一个平衡规则,换言之就是这样子的情况就是打破了平衡规则。然后定睛一看,就是两个右边的节点(RR)打破的所以就直接按照上面的RR调整先调整次序,使得38原来指向46的箭头变成指向50(新的父结点)。然后又因为一个b树的中间节点一定要是黑色的并且左右两边的数据要是红色的所以就
“换颜色!”
对,46,52变成红色,50就变成黑色。
一个新的红黑树崭新出厂。。。。
当然同样的72,60,76那一个子树也是同理。
接下来就是RL和RR了。
拿RL举例子,就是46,50,48这一栏的。调节顺序还是一样的,先判断是哪一个地方打破了平衡规则,那这里很明显就是48,50是两个红色节点不能相邻来连接。然后看到是RL的类型就是直接按照上面的调整方法直接调整。把38原来指向46的箭头指向48(因为RL调整之后48是新的父结点),然后46,50都是左右的两个子节点。接着就是调色,因为四阶b树的父结点要求是黑色的,所以48变成黑色,左右两边的46,50变成红色。然后。
一个调整过后的新的红黑树,崭新出厂。。。。
(如下图)
情况四:如果你想插入的地方已经满了(已经有叔节点了)
比方说这里你想插入一个10,但是违反了“红色节点不能相邻链接”的规则,这个时候应该怎么办?
我们选取一个节点进行向上合并。根据红黑树转化为b树的规则,向上合并只能够是红色的节点,所以25变成红色。
这个时候我们先只看25,17,33这一个小子树并只对这个小树分析。那既然你已经没有位置了我们只能换颜色来创造位置。所以我们把17,33变成黑色(可以插入一个新的红色节点的黑色)。
然后就会变成这样:
“你这不是还是有两个红色的节点相邻链接嘛,你这也不行啊。”
不是哥们,那我们用上面讲到的LL类型变换一下不就是崭新出厂嘛。
就是如果出现了新问题就是参考已有的方法进行解决。
同样的,RL同理
以上就是大致的插入情况了,下面就是删除操作。
删除操作:
情况一:标准删除红色节点
在不打破平衡规则的情况之下删除红色节点你想咋地就咋地。不需要额外操作。
情况二:标准删除根节点
同样的,在不打破平衡的情况下你想咋地就咋地。不需要额外操作。
情况三:删除拥有一个红色节点的黑色节点。
比方说我现在需要删除46和76.那我按照以下步骤走
- 先把55指向46的箭头更改为指向50,同样的80指向76的箭头更改为指向72。
- 删除46,76。
然后变成这样:
- 又因为你看,80和72是两个红色节点相邻链接,所以就要把72换颜色换成黑色的(以为55和80已经合并了那方便起见就直接让72换颜色而不让80换颜色)。同样的,55没有合并上去所以55也变成黑色。(你要是理解成方便下一次数据的插入也对。)
然后就会变成这样:
情况四:删除的黑色节点只有没有红色节点
比方说这一种情况,我想要删除88。但是我不可以直接删除88,因为按照b树规则每一个节点起码要有一个元素。所以我们按照下面的步骤来:
- 先直接删除88,然后变成这样。
- 瓦这不就是RL类型嘛,直接RL类型转他变成这样
这样子原来88所在的结点还是保留了一个元素(80),所以符合b树的规则。
情况五:如果删除的兄弟节点没有红色节点
比方说现在这样,我想删除88,但是你知道的就像上面说的一样,b树的结点最少要有一个元素,上面的方法是向兄弟节点拿了一个红色,那么这次应该怎么办呢?
- 直接删除88,变成这样
2.把88移下来然后把76变成红色的节点。(本质上就是红色的节点可以“移动”填补到需要的地方)
然后就可以崭新出厂了。。。