红黑树-新增


整体流程

  • 红黑树特性
  • 红黑树操作
  • 红黑树新增时的情况
  • 新增后会做的操作详解

看的时候配合着目录, 有根据的看

红黑树的特性

因为红黑树也是一种二叉树, 所以先说二叉查找树的特性

二叉查找树特性

  1. 左节点小于父节点
  2. 右节点大于父节点

红黑树特性

  1. 节点的颜色不是红色, 就是黑色
  2. 根节点和叶子节点都是黑色
  3. 红色节点的子节点必须是黑色
  4. 每一个节点, 当前节点到可达叶子节点的所有路径上, 黑色节点数量相同
    1. 黑色完美平衡

红黑树的操作

  • 变色
  • 旋转
    • 左旋
    • 右旋

变色

变色就是为了满足红黑树的特性, 把节点变红或变黑

旋转

怎么旋转:

要旋转的节点围绕着子节点进行旋转(以子节点为圆心, 此时子节点称为圆心节点)

旋转方向怎么称呼:

以上北下南的上北, 为参照方向
向左, ????, 就是左旋, 逆时针
向右, ????, 就是右旋, 顺时针

怎么判定旋转方向:

  1. 比较当前节点与圆心节点值的大小
  2. 最短路径

如图1
假如500节点要旋转, 根据上述旋转操作特性
因为500小于600, 且要最短路径, 且要围绕子节点进行旋转
所以500节点绕着子节点, 左旋

图2
同理, 可以推断出, 假如500节点要旋转, 是要绕着400节点右旋的

左旋右旋节点的变化

左旋
要旋转的节点变成圆心节点的新左节点
要旋转的节点的右节点, 连接圆心节点的原左节点

右旋
原理同左旋, 变换一下方向即可

如图3
在不考虑平衡的情况下, 假如500节点要围绕着650节点左旋
那么500节点变成650节点的左节点
然后, 500节点的新右节点连接600节点(650节点的原左节点)
见图4

图4


红黑树的新增

节点介绍

为了方便记忆, 先介绍几个节点

如图5
700节点的视角出发

  • 700节点 称为C, current, 当前节点
  • 600节点 称为B, brother, 700节点的兄弟节点
  • 650节点 称为P, parent, 700节点的父节点
  • 500节点 称为G, grandfather, 700节点的祖父节点
  • 400节点 称为U, uncle, 700节点的叔叔节点

如果叔叔或者兄弟节点是叶子节点, 也就是黑色的nil节点, 那也把它看成成员的一个

如图6
假如新增一个800节点, 那此时, 800节点为C, B和U虽然是nil节点
但它也看成C的叔叔和兄弟, 把它们也看成黑色的节点

介绍总结

红黑树自平衡的最小单元, 由CPGU组成
换句话说, 每次红黑树需要进行自平衡时, 只关注CPGU这四个节点即可

新增介绍

新增的节点, 默认红色

新增的情况有哪些

新增一个节点, 默认红色

  1. 没有父节点
  2. 有父节点, 父节点是黑色
  3. 有父节点, 父节点是红色, 叔叔节点是黑色, CPG在同一条直线上
  4. 有父节点, 父节点是红色, 叔叔节点是黑色, CPG不在同一条直线上
  5. 有父节点, 父节点是红色, 叔叔节点是红色

新增一个节点, 因为节点是红色, 都要看一看是否违反了红黑树的特性, 是的话, 则需要自平衡
下面会一一解释这些情况, 然后提供图片

新增分析

下面我们把新增节点都称为C

1. 没有父节点

需要做的操作

  1. 变色

如果没有父节点, 那么新增的节点C就是根节点root
新增后, 为了满足红黑树特性2, C变红色为黑色, 新增结束

2. 有父节点, 父节点是黑色

需要做的操作

因为父节点是黑色, 新增一个红色节点, 不破坏红黑树的特性
所以不需要操作

3. 有父节点, 叔叔节点是黑色, CPG在同一条直线上

什么叫CPG在同一条直线上

如图
假如要新增一个1000节点C, 那么此时, 不考虑旋转之前, CPG是在同一条直线上

需要做的操作

  1. 要旋转G节点, 以P节点为圆心
  2. GP颜色互换

如上图
新增1000节点C, 因为红色C不满足红黑树特性3
假如先把C变为黑色, 那就不满足红黑树特性4, 还是需要调整
所以, 新增C后, 先做的操作是, 以P为圆心, 左旋G
然后G变成红色, P变成黑色
此时整棵树还是满足红黑树特性
见下图

4. 有父节点, 父节点是红色, 叔叔节点是黑色, CPG不在同一条直线上

什么叫CPG不在同一条直线上

如图
假如要新增一个850节点, 那么此时, 不考虑旋转之前, CPG不在同一条直线上

需要做的操作

  1. 以C为圆心, 旋转P(右旋)
  2. 此时, 把原P变成了C, 把原C变成了P
  3. 此时情况变成了情况3, 继续按照情况3的操作进行

如上图
新增节点C, 850
以C为圆心, 右旋P
见下面两张图

变情况3, 继续情况3操作
以P为圆心, 左旋G节点
GP颜色互换

5. 有父节点, 父节点是红色, 叔叔节点是红色

需要做的操作

  1. P节点变为黑色
  2. U节点变为黑色
  3. G节点变为红色
  4. 以G节点视角出发, 将G节点看做C节点, 看看满足新增的哪种情况, 递归操作

如图
新增1000节点C. 此时, P, U为红色, G为黑色
PU两节点变为黑色, G变为红色
接着, 从G的视角出发, 把G当做新的C, 然后向上看, 满足新增的哪种情况
见下图

此时的情况符合情况5, (有父节点, 父节点是红色, 叔叔节点是红色)
PU变为黑色, 此时G变为红色
如下图, G又成为新的C, 此时的情况符合情况1, 新C变为黑色
自平衡结束, 符合红黑树全部特性

总结

  1. 没有父节点
    1. 变色
  2. 有父节点, 父节点是黑色
  3. 有父节点, 父节点是红色, 叔叔节点是黑色, CPG在同一条直线上
    1. 要旋转G节点, 以P节点为圆心
    2. GP颜色互换
  4. 有父节点, 父节点是红色, 叔叔节点是黑色, CPG不在同一条直线上
    1. 以C为圆心, 旋转P(右旋)
    2. 此时, 把原P变成了C, 把原C变成了P
    3. 此时情况变成了情况3, 继续按照情况3的操作进行
  5. 有父节点, 父节点是红色, 叔叔节点是红色
    1. P节点变为黑色
    2. U节点变为黑色
    3. G节点变为红色
    4. 以G节点视角出发, 将G节点看做C节点, 看看满足新增的哪种情况, 递归操作

参考文档

https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
https://www.bilibili.com/video/BV1SJ41117r1