1、定义
红黑树(Red-Black Tree)是一种自平衡(通过在插入和删除节点时进行变换颜色和旋转的调整,保持树的大致平衡,从而确保这些操作的时间复杂度最差也为O(log n)的二叉搜索树,在计算机科学中用于实现高效的数据查找、插入和删除操作
2、特性
颜色
1. 每个节点都是红色或黑色。(用于通过颜色控制平衡)
2. 根节点是黑色。(简化临界条件,简化逻辑)
3. 所有叶子节点(NIL节点,即空节点)都是黑色。(简化临界条件,简化逻辑)
规则
4. 红色节点的两个子节点都是黑色(即红色节点不能有红色子节点)。(限制红色节点的连续性,避免树高度过高,引起不平衡)
5. 从任一节点到其每个叶子的所有路径上具有相同数目的黑色节点。(即黑高相同,强制各路径长度大致相同,从而控制树高,从而保证了操作时间复杂度在O(log n)内)
3、操作
红黑树在插入和删除节点时通过旋转(平衡树高)和重新着色(变相维持平衡)来维持其平衡状态
对E左旋(将右子树的高度一定程度左移):
对S右旋(将左子树的高度一定程度右移):
附带测试网址 Red/Black Tree VisualizationRed/Black Tree VisualizationRed/Black Tree Visualization
1、查
1. 从根节点开始:
- 查询操作从红黑树的根节点开始。
2. 逐层比较:
- 比较要查找的值(键)与当前节点的值。
- 如果要查找的值等于当前节点的值,则查找成功,返回该节点。
- 如果要查找的值小于当前节点的值,则移动到当前节点的左子节点,继续比较。
- 如果要查找的值大于当前节点的值,则移动到当前节点的右子节点,继续比较。
2、增
1、查找插入节点的位置
按照第一点 查 的比较方式找到合适的位置
2、插入新节点
新节点总是插入为红色(不会影响黑高,这有助于保持红黑树的平衡)
3、修复树
1:新节点是根节点
如果新节点是根节点,则将其颜色改为黑色。
2:新节点的父节点是黑色
如果新节点的父节点是黑色,插入操作完成,红黑树的性质没有被破坏。
3:新节点的父节点是红色
如果新节点的父节点是红色,则需要进一步处理。假设新节点为N,父节点为P,祖父节点为G,父节点的兄弟节点(叔叔节点)为U。
- 3.1:叔叔节点U是红色
1、将P和U都涂黑,G涂红。(相当于将黑节点均衡向各路径下移,有助于保持各路径黑高相同)
eg:插入节点35→节点15、50变黑
2、以G为当前节点,继续修复。
eg:接上修复节点30也为黑(根节点)
- 3.2:叔叔节点U是黑色
1、旋转P使得G、P、N三点的路径为一条直线(这样做可以简化后续的旋转操作,如果本身G-P-N就为一条直线则无需旋转)
eg:插入节点59→左旋节点57,使得节点60、57、59在一条直线
2、往路径短的一侧旋转G以平衡
eg:右旋节点60
3、将新P涂黑,将原G涂红。消除连续红色冲突(上述规则4,可以限制红色节点的连续性,避免树高度过高,引起不平衡)
eg:将节点59涂黑,节点60涂红
3、删
1、查找删除节点的位置
按照第一点 查 的比较方式找到合适的位置
2、删除旧节点
- 1、删除的节点没有子节点(也就说删除的节点是叶子节点):直接删除该节点。
- 如果删除的是红色叶子节点情况,黑高不受影响,不需要进行修复。
要修 - 如果删除的是黑色叶子节点情况,当前路径黑高减少,因此需要进行修复。
- 2、 删除的节点有一个子节点(这个子节点不会有子树,否则会导致黑高不一致):删除该节点,并用其子节点代替。
- 如果删除的是红色节点,黑高不受影响,不需要进行修复。
- 如果删除的是黑色节点,并且其子节点是红色,这种情况下,将子节点替代删除的节点并将子节点涂黑,处理后黑高在删除前后未变,因此不需要进行修复。
要修 - 如果删除的是黑色节点,并且其子节点是黑色,这时黑高改变,因此需要进行修复。
- 3、删除的节点有两个子节点:找到该节点的后继节点(即右子树中最小的值,也即右子树中最左边的节点),将后继节点的值复制到待删除节点,然后删除后继节点(最终会简化为上述2)
3、修复树
针对以上删除操作后若黑高发生改变,需要平衡红黑树则以下进行不同场景下的操作,否则不需要修复(假设x为删除后的代替节点)
1: x 是新根节点
直接将其涂黑
eg:删除节点15→用后继节点12代替→将节点12涂黑
2: x 的兄弟节点 w 是红色
1、将 w 涂黑,x 的父节点涂红。
2、往路径短的一侧旋转w 的父节点以平衡
eg:删除节点76(此时x为NIL节点)→将节点21涂黑,将56涂红→对节点56进行右旋
eg:删除节点76→右旋节点38
eg:左旋节点39
eg:右旋节点56
eg:将节点40涂红,节点39、56涂黑
3: x 的兄弟节点 w 是黑色
- 3.1: w 的两个子节点都是黑色
1、将 w 涂红。
2、 将 x 的父节点赋值给 x。
eg:在上述情况2的结果中
将节点38涂红,将节点56涂黑
- 3.2: w 的一个子节点是红色,一个子节点是黑色
1、 将w及其父子节点通过旋转w使得三点的路径为一条直线(这样做可以简化后续的旋转操作,如果w及其父子节点本身就为一条直线则无需旋转)
eg:删除节点12→旋转节点56使得节点21、38、56在一条直线
2、往路径短的一侧旋转w 的父节点以平衡
eg:左旋节点21
3、将w涂红,子涂黑
eg:将节点38涂红,节点21、56涂黑
4、改
即删除后再进行插入操作
5、操作的核心原则
旋转:旋转时遵循如果子节点一侧没节点,则先将子旋转到一侧方便后续平衡(比如之前的G-P-N一条线),然后旋转父节点给路径短的另一侧进行平衡(旋转G);
变色:黑色节点尽量下移有助于保持平衡,红色不能连续,然后结尾看看黑高是否相同
4、与其他树之间的关系
二叉树(二叉树是最基本的形式,定义了每个节点最多有两个子节点。最简单的形式,没有特殊的约束)
⬇
二叉搜索树(是二叉树的一种扩展,增加了节点值的有序性要求,左小右大。保证了节点值的有序性,但在最坏情况下会退化成线性结构)
⬇
红黑树(二叉搜索树的一种自平衡扩展,通过颜色和规则确保平衡性。确保了查找、插入和删除操作在最坏情况下的高效性)