红黑树

1.红黑树的意义


  二叉查找树在极端的插入情况下,操作时间复杂度会变为O(n),但是*衡二叉树可以一直维持在O(lg(n))。因此*衡二叉查找树的效率很高,红黑树是一种自*衡二叉查找树的实现方式,这便是红黑树的意义。

2.红黑树性质


  [1]节点是红色或黑色。

  [2]根节点是黑色。

  [3]每个叶节点(NIL节点,空节点)是黑色的。

  [4]每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

  [5]从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

3.变色、左旋和右旋


  变色的目的是进行操作后可以(更趋*于)保持红黑树的性质。

  左旋和右旋是变更节点在树中的位置,目的是进行这些操作后可以(更趋*于)保持红黑树的性质。

4.删除操作


  红黑树的删除和二叉查找树的删除操作是一样的,只是多了一个修复*衡的流程。  

  整体流程:首先按照二叉查找树的方式删除节点。之后判断释放节点的颜色,如果是红色,则结束,否则进入修复流程,修复流程就是一个状态机,直到走到完成状态。

  [1]按照二叉查找树的删除流程:

    1)如果删除节点的右子树为空,则把左节点接到删除节点位置。此时,删除节点就是释放节点。
    2)如果删除节点的左子树为空,则把右节点接到删除节点位置。此时,删除节点就是释放节点。
    3)如果左右都不为空,则把删除节点的左子树的最右节点(释放节点,也就是删除节点的后继节点)替换到要删除的节点,然后把释放节点的左子树接到其父节点上面。此时,后继节点就是释放节点。
  [2]如果释放节点的颜色是红色,则操作结束。否则,释放节点的颜色是黑色,并且释放节点只可能最多有一个子节点,把释放节点(删除节点或者后继节点)的子节点作为当前节点,释放节点的父节点作为父节点,进入状态机。

  [3]修复(状态机),循环执行以下操作:

    1)如果当前节点是红色,则把当前节点涂黑,操作结束。

    2)如果当前节点是黑色,且兄弟节点是红色,则进行操作:兄弟节点涂黑,父节点涂红,对父节点进行左旋。(此时,当前节点的父节点没变,但是兄弟节点变为黑色)。

    3)如果当前节点是黑色,且兄弟节点是黑色,且兄弟节点的两个子节点都是黑色,则进行操作:兄弟节点涂红,将父节点作为当前节点(附带的操作就是更新父节点为之前节点的祖父节点)。

    4)如果当前节点是黑色,且兄弟节点是黑色,且兄弟节点的右子节点是黑左子节点是红,则进行操作:兄弟节点涂红,兄弟左子节点涂黑,对兄弟节点进行右旋。(此时,当前节点的父节点没变,但是兄弟节点的右子节点变为红色)。

    5)如果当前节点是黑色,且兄弟节点是黑色,且兄弟节点的右子节点是红左子节点任意,则进行操作:兄弟节点的颜色涂成父节点的颜色,父节点涂黑,兄弟节点的右子节点涂黑,对父节点进行左旋,将根节点涂黑,操作结束。

    以上是当前节点是父节点左子节点的情况,如果是右子节点,只是做了对称处理(例如,对某个状态,作为左子节点时做左旋,而作为右子节点做右旋)。

5.插入操作


  红黑树的删除和二叉查找树的插入操作是一样的,只是多了一个修复*衡的流程。

  整体流程:首先按照二叉查找树的方式插入节点,把插入节点涂红。之后进入修复流程,修复流程就是一个状态机,直到走到完成状态。最后把根节点涂黑。

  [1]按照二叉查找树的插入流程:小于根的往左子树递归插入,否则往右子树递归插入。插入的节点必定是插到最下面那一层,不会插入到树的中间位置。

      初始把刚插入的节点涂红(涂红不会影响规则5,因此只需要处理更少的条件),把刚插入的节点作为当前节点。

  [2]修复(状态机),循环执行以下操作:

    1)如果当前节点的父节点是空,状态机完成。

    2)如果当前节点的父节点是黑色,状态机完成。

    3)如果当前节点的父节点是红色,叔叔节点是红色,则执行操作:将当前节点的父节点涂黑,叔叔节点涂黑,祖父节点涂红,再将祖父节点作为当前节点。

    4)如果当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右子节点,则执行操作:对当前节点的父节点执行左旋,并把当前节点的父节点作为当前节点(附带更新当前节点的父节点(就是之前的节点))。

    5)如果当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左子节点,则执行操作:对当前节点的父节点涂黑,祖父节点涂红,对祖父节点执行右旋。

    最后把根节点涂黑,结束。

    以上是当前节点是父节点左子节点的情况,如果是右子节点,只是做了对称处理(例如,对某个状态,作为左子节点时做左旋,而作为右子节点做右旋)。

6.总结


  [1]红黑树的插入和删除和二叉查找树的方式是一样的,之后多了一个修复流程,主要就是修复流程的状态机,对于某一个状态来说,需要进行一系列的操作,进行这个操作的目的是为了进入下一个状态,下一个状态肯定更趋*于树的*衡。

  [2]关于变色、左旋和右旋,这些操作的目的是为了让树的当前状态更趋于*衡,这个也是处理红黑树的关键,即什么时候需要变色、旋转,为何变色、旋转后可以更趋*于*衡,这个也需要在实践中熟练。

  [3]对于插入修复状态机的第4个状态说明:"对当前节点的父节点执行左旋",这个操作结束后,当前节点和父节点的位置会互换,因此把父节点作为当前节点后,当前节点的父节点就是之前的节点,代码就是:

1
2
3
4
5
register struct rb_node *tmp;
__rb_rotate_left(parent, root);        //对父节点左旋
tmp = parent;                          //
parent = node;                         //父节点作为当前节点,同时更新当前节点的父节点
node = tmp;                            //

  [4]代码,参照linux内核红黑树源码。

posted on   能量星星  阅读(165)  评论(0编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示