六、图解红黑树

六、图解红黑树

6.1 红黑树的五条规则

红黑树除了符合二叉搜素树的基本规则外,还添加了以下特性:

  • 节点是红色或黑色

  • 节点是黑色

  • 每个叶子节点都是黑色的空节点(NIL节点)

  • 每个红色节点的两个子节点都是黑色的(从每个叶子到根的所有路径上,不可能有两个连续红色节点)

  • 任意节点到其每个叶子节点的所有路径,都包含相同数目的黑色节点

6.2 红黑树的相对平衡

前面5条规则的约束确保了以下红黑树的关键特性:

  • 从根到叶子节点的最长路径,不会超过最短路径的两倍;

  • 结果就是这棵树基本是平衡的;

  • 虽然没有做到绝对的平衡,但是可以保证在最坏的情况下,该树依然是高效的;

为什么可以做到最长路径不超过最短路径的两倍呢?

  • 性质4决定了路径上不能有两个相连的红色节点;

  • 所以,最长路径一定是红色节点和黑色节点交替而成的;

  • 由于根节点和叶子节点都是黑色的,最短路径可能都是黑色节点,并且最长路径中一定是黑色节点多于红色节点;

  • 性质5决定了所有路径上都有相同数目的黑色节点;

  • 这就表明了没有路径能多于其他任何路径两倍长。

6.3 红黑树的三种变换

插入一个新节点时,有可能树不再平衡,可以通过三种方式的变换使树保持平衡

  • 变色

  • 左旋转

  • 右旋转

变色

为了重新符合红黑树的规则,需要把红色节点变为黑色,或者把黑色节点变为红色;

插入的新节点通常都是红色节点

  • 当插入的节点为红色的时候,大多数情况不违反红黑树的任何规则

  • 而插入黑色节点,必然会导致一条路径上多了一个黑色节点,这是很难调整的;

  • 红色节点虽然可能导致红红相连的情况,但是这种情况可以通过颜色调换和旋转来调整;

左旋转

节点X为根逆时针旋转二叉搜索树,使得父节点原来的位置被自己的右子节点替代,左子节点的位置被父节点替代;

![C%M0XTP1MTHVPRQKV{78BHU.png](https://img-blog.csdnimg.cn/img_convert/b0361c61c4eac2954ef2ead86c07e4cf.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u2b443193&margin=[object Object]&name=C%M0XTP1MTHVPRQKV{78BHU.png&originHeight=261&originWidth=521&originalType=binary&ratio=1&rotation=0&showTitle=false&size=85963&status=done&style=none&taskId=ucb421ef7-f3ed-41af-9960-4d502a33ae7&title=)

如上图所示,左旋转之后:

  • 节点X取代了节点a原来的位置;

  • 节点Y取代了节点X原来的位置;

  • 节点X的左子树 a 仍然是节点X的左子树(这里X的左子树只有一个节点,有多个节点时同样适用,以下同理);

  • 节点Y的右子树 c 仍然是节点Y的右子树;

  • 节点Y的左子树 b 向左平移成为了节点X的右子树;

除此之外,二叉搜索树左旋转之后仍为二叉搜索树

右旋转

以节点X为根顺时针旋转二叉搜索树,使得父节点原来的位置被自己的左子节点替代,右子节点的位置被父节点替代;

![PK4YTWTZT4W(1S2NOP}N3U.png](https://img-blog.csdnimg.cn/img_convert/bb4a3081608b5e09e9d988883d25be7f.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ub2fcaeb9&margin=[object Object]&name=PK4YTWTZT4W(1S2NOP}N3U.png&originHeight=238&originWidth=536&originalType=binary&ratio=1&rotation=0&showTitle=false&size=76220&status=done&style=none&taskId=uf9a0ad63-a271-4ca0-bc88-cb98df70c7d&title=)

如上图所示,右旋转之后:

  • 节点X取代了节点a原来的位置;

  • 节点Y取代了节点X原来的位置;

  • 节点X的右子树 a 仍然是节点X的右子树(这里X的右子树虽然只有一个节点,但是多个节点时同样适用,以下同理);

  • 节点Y的左子树 b 仍然是节点Y的左子树;

  • 节点Y的右子树 c 向右平移成为了节点X的左子树;

除此之外,二叉搜索树右旋转之后仍为二叉搜索树

6.4 红黑树的插入操作

首先需要明确,在保证满足红黑树5条规则的情况下,**新插入的节点必然是红色节点。 **

为了方便说明,规定以下四个节点:

  • 新插入节点为N(Node)

  • N的父节点为P(Parent)

  • P的兄弟节点为U(Uncle)

  • U的父节点为G(Grandpa)

  • 如下图所示:

C$KI3JRTI.png

情况一(根)

  • 当插入的新节点N位于树的根上时,没有父节点

  • 这种情况下,只需要将红色节点变为黑色节点即可满足规则2 。

![BF76_CPK~}C0Z4S(VLP92UV.png](https://img-blog.csdnimg.cn/img_convert/e8c0e3f1c2ffcf36a6ebf4cb65d50112.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u78e44705&margin=[object Object]&name=BF76_CPK~}C0Z4S(VLP92UV.png&originHeight=184&originWidth=201&originalType=binary&ratio=1&rotation=0&showTitle=false&size=11516&status=done&style=none&taskId=ua1ddf092-8c16-4bf1-b67a-1976b5b76a4&title=)

情况二(P为黑)

  • 新节点N的父节点P为黑色节点,此时不需要任何变化。

  • 此时既满足规则4也满足规则5。尽管新节点是红色的,但是新节点N有两个黑色节点NIL,所以通向它的路径上黑色节点的个数依然相等,因此满足规则5 。

情况三(父红叔红祖黑)

节点P为红色,节点U也为红色,此时节点G必为黑色,即父红叔红祖黑。

在这种情况下需要:

  • 先将父节点P变为黑色;

  • 再将叔叔节点U变为黑色;

  • 最后将祖父节点G变为红色;

  • 即变为父黑叔黑祖红,如下图所示:

![YBE%JSE[{VWTR)MWJZJ(}8N.png](https://img-blog.csdnimg.cn/img_convert/80de81bfbafc581a58218a1149ff8262.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=uc3bedd42&margin=[object Object]&name=YBE%JSE[{VWTR)MWJZJ(}8N.png&originHeight=342&originWidth=562&originalType=binary&ratio=1&rotation=0&showTitle=false&size=50302&status=done&style=none&taskId=ubad75806-6a25-4a7e-9185-d76ce1c08ac&title=)

可能出现的问题:

  • N的祖父节点G的父节点也可能是红色,这就违反了规则4,此时可以通过递归调整节点颜色

  • 递归调整到根节点时就需要旋转了,如下图节点A和节点B所示,具体情况后面会介绍;

情况四(父红叔黑祖黑,左节点,右旋转

节点P是红色节点,节点U是黑色节点,并且节点N为节点P的左子节点,此时节点G一定是黑色节点,即父红叔黑祖黑

在这种情况下需要:

  • 先变色:将父节点P变为黑色,将祖父节点G变为红色

  • 后右旋转:以祖父节点G为根进行右旋转

![@}GV{[KWAR$7D2S(D2KFVO.png](https://img-blog.csdnimg.cn/img_convert/31c2f3e7cdb880734716c0ed8f9910b7.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=196&id=u3cdca7aa&margin=[object Object]&name=@}GV{[KWAR$7D2S(D2KFVO.png&originHeight=229&originWidth=619&originalType=binary&ratio=1&rotation=0&showTitle=false&size=54237&status=done&style=none&taskId=ue3917267-e1c2-48b4-bdc7-d1ecf300b6c&title=&width=529)

情况五(父红叔黑祖黑,右节点,左旋转

节点P是红色节点,节点U是黑色节点,并且节点N为节点P的右子节点,此时节点G一定是黑色节点,即父红叔黑祖黑

在这种情况下需要:

  • 先以节点P为根进行左旋转,旋转后如图b所示;

  • 随后将红色节点P和黑色节点B看成一个整体的红色节点N1,将新插入的红色节点N看成红色节点P1 如图c所示。此时整体就转换为了情况4。

![UKaTeX parse error: Expected 'EOF', got '}' at position 4: H~C}̲7Y39HFR)G3(5_%K…H~C}7Y39HFR)G3(5_%KQ9.png&originHeight=219&originWidth=568&originalType=binary&ratio=1&rotation=0&showTitle=false&size=47683&status=done&style=none&taskId=u3af2a321-5adf-4fd2-bac2-3746680674b&title=)

接着可以按照情况4进行处理:

  • 先变色:将N1节点的父节点P1变为黑色,将祖父节点G变为红色;

  • 后旋转:以祖父节点G为根进行右旋转,旋转后如图 e所示;
    最后将节点N1和P1变换回来,完成节点N的插入,如图所示;

6.5 红黑树的案例

在二叉树中依次插入:10,9,8,7,6,5,4,3,2,1

插入10

符合情况一

  • 插入节点10

  • 将节点10的颜色变为黑色

![N%(1N)G~)LA1XAYQHOBSY3X.png](https://img-blog.csdnimg.cn/img_convert/0f090edce6aafe3f2e98b42e8dcab2ac.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u42cd83a9&margin=[object Object]&name=N%(1N)G~)LA1XAYQHOBSY3X.png&originHeight=113&originWidth=121&originalType=binary&ratio=1&rotation=0&showTitle=false&size=16746&status=done&style=none&taskId=u40a6d346-3cb8-4ea8-8cc4-35b7b18bfc9&title=)

插入9

符合情况二

  • 插入节点9

  • 不需要任何情况

![S@_OB2Q15Q6I()92KaTeX parse error: Expected 'EOF', got '#' at position 89: …57113c2676a.png#̲clientId=ud3846…WNGM7B.png&originHeight=237&originWidth=228&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38836&status=done&style=none&taskId=u71f642b2-5d87-4d96-b0a4-074e2b25166&title=)

插入8

符合情况四

  • 插入节点8

  • 先变色,9 -> 黑 ,10 -> 红

  • 以祖父节点10为根右旋转

![{CG)F[[5C{FVCYUFA${AXO.png](https://img-blog.csdnimg.cn/img_convert/9323f07fcc3e7077763db7d2aa26e64b.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u5b1332ea&margin=[object Object]&name={CG)F[[5C{FVCYUFA${AXO.png&originHeight=287&originWidth=657&originalType=binary&ratio=1&rotation=0&showTitle=false&size=91636&status=done&style=none&taskId=uec42414a-47e1-4e50-b2d2-024b062c751&title=)

插入7

符合情况三

  • 插入节点7

  • 先变色,8,10 -> 黑 , 9 -> 红

  • 再把祖父元素9变为黑色

![RX{8~LZIV3KaTeX parse error: Expected 'EOF', got '#' at position 95: …32e99e55baf.png#̲clientId=ud3846…XES0]0EYRB8S.png&originHeight=301&originWidth=1010&originalType=binary&ratio=1&rotation=0&showTitle=false&size=163407&status=done&style=none&taskId=uea6630b7-c4c4-4931-adc4-1abd3c17ae0&title=&width=560)

插入6

符合情况四

  • 插入节点6

  • 先变色,7 -> 黑 , 8 -> 红

  • 以祖父节点8为根右旋转

![M0YG@D95]TTKaTeX parse error: Expected '}', got 'EOF' at end of input: FV{`FUTI%Y.png](https://cdn.nlark.com/yuque/0/2022/png/25602002/1657201700973-f6835b0f-be4d-4dca-b2c6-0891febe8e4d.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&height=202&id=u0e8a997a&margin=%5Bobject%20Object%5D&name=M0YG%40D95%5DTT%24FV%7B%60FUTI%24%25Y.png&originHeight=389&originWidth=1064&originalType=binary&ratio=1&rotation=0&showTitle=false&size=195451&status=done&style=none&taskId=u086db68c-4f35-4a5a-98b0-c31348079ca&title=&width=552)

插入5

符合情况三

  • 插入节点5

  • 先变色,6,8 -> 黑 , 7 -> 红

![{I_(]72Y(N0)7CFU45_%S.png](https://img-blog.csdnimg.cn/img_convert/02517af7b19e52a042b332a4c8171990.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=uca8492e2&margin=[object Object]&name={I_(]72Y(N0)7CFU45_%S.png&originHeight=377&originWidth=896&originalType=binary&ratio=1&rotation=0&showTitle=false&size=138039&status=done&style=none&taskId=u0659d59a-9ea3-4452-84aa-4121d3422db&title=)

插入4

符合情况四

  • 插入节点4

  • 先变色,5 -> 黑 , 6 -> 红

  • 以祖父节点6为根右旋转

![6EQ[G]D{T2{}2VZ7@E@I7MY.png](https://img-blog.csdnimg.cn/img_convert/8ed8ee781b05b053719c6dd108f91159.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u47cbeae9&margin=[object Object]&name=6EQ[G]D{T2{}2VZ7@E@I7MY.png&originHeight=441&originWidth=1128&originalType=binary&ratio=1&rotation=0&showTitle=false&size=279110&status=done&style=none&taskId=ub9d8151e-f1b3-4294-bd9c-931b005faee&title=)

插入3

符合情况3

  • 插入节点8

  • 先变色,4,6 -> 黑 , 5 -> 红


  • 变换之后发现5,7为相连的两个红色节点,于是把以5为根的整个子树看成一个新插入的节点N1,再进行第二次变换。

符合情况4

  • 插入节点N1

  • 先变色,7-> 黑 , 9 -> 红


  • 以祖父节点9为根右旋转

![OKM_Y8W31H@@UHH04}LUH)U.png](https://img-blog.csdnimg.cn/img_convert/4b8cf87191374550fb9a6721d81a1b3e.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u95421947&margin=[object Object]&name=OKM_Y8W31H@@UHH04}LUH)U.png&originHeight=492&originWidth=1141&originalType=binary&ratio=1&rotation=0&showTitle=false&size=354605&status=done&style=none&taskId=u930a268e-63cb-4271-94f4-255755f51cd&title=)

插入2

符合情况四

  • 插入节点2

  • 先变色,3 -> 黑 , 4 -> 红

  • 以祖父节点4为根右旋转

![4]OUHWUC6M43[V@O_FSVJA.png](https://img-blog.csdnimg.cn/img_convert/d37a66f5354cf654870417eeae57fa69.png#clientId=ud38460c5-73fc-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ubfcd3c14&margin=[object Object]&name=4]OUHWUC6M43[V@O_FSVJA.png&originHeight=440&originWidth=1154&originalType=binary&ratio=1&rotation=0&showTitle=false&size=304017&status=done&style=none&taskId=ufd04b308-45d9-453f-8753-76b168f7b58&title=)

插入1

符合情况三

  • 插入节点1

  • 先变色,2,4 -> 黑 , 3 -> 红

  • 变换之后发现3和5为相连的两个红色节点,于是把以3为根的整个子树看成一个新插入的节点N1,再进行第二次变换。

符合情况三

  • 插入节点N1

  • 先变色,5,9 -> 黑 , 7 -> 红

  • 变换之后发现根节点7为红色不符合规则2,所以把以7为根节点的红黑树看成一个新插入的节点N2,再进行第三次变换。

符合情况一

  • 插入节点N2

  • 变色,7 -> 黑


![BTGXH@KaTeX parse error: Expected group after '_' at position 10: ZP11P(0~(_̲_5}HCV.png](htt…ZP11P(0~(__5}HCV.png&originHeight=455&originWidth=1163&originalType=binary&ratio=1&rotation=0&showTitle=false&size=335741&status=done&style=none&taskId=u5052fe83-b6a9-4ce7-863b-80394815600&title=)

6.6 红黑树的删除操作


红黑树的删除操作结合了复杂的二叉树的删除操作和复杂的红黑树的插入规则,整体来说难度非常大,篇幅较长,这里暂不进行探讨。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呐呐呐呐。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值