博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
红黑树
阅读量:5814 次
发布时间:2019-06-18

本文共 5069 字,大约阅读时间需要 16 分钟。

红黑树是一种自平衡二叉查找树,具有在最坏情况下查找、插入、删除O(log2n)的复杂度。红黑树中从根节点到任意一叶子节点的最长路径不超过最短路径的两倍,因此是一种近似平衡的二叉树。

节点信息

    红黑树的节点具有如下信息:

struct RBNode{	int data;			//数据	int color;			//颜色,红或者黑	RBNode* parent;		//父节点	RBNode* child[2];	int child_dir;		//指示当前节点是其父节点的左还是右子节点	RBNode(int d){		data = d;		color = RED; 		parent = NULL;		child[0] = child[1] = NULL;	}};

 

红黑树性质

    红黑树满足如下性质:

  1. 每个节点或者是黑色或者是红色
  2. 树的根节点为黑色
  3. 树的叶节点(NIL)为黑色(为了表示方便红黑树中所有有效叶子节点<含有数据的叶节点>都添加了额外的叶子节点为NIL, 这里是指NIL为黑色)
  4. 如果一个节点是红色,则它的两个子节点均为黑色
  5. 对每个节点,从该节点到其子孙叶节点上的所有路径上包含有相同数目的黑节点

    对于满足如上条件的红黑树,则有以下引理:

一棵有n个内节点的红黑树的高度至多为 2*log2(n+1)

因此红黑树的操作复杂度最坏为 O(log2n)

红黑树的旋转

    和AVL树、Splay树、Treap一样,红黑树实现其平衡性也是通过节点的旋转(以及对节点重新染色)来实现。红黑树的旋转具有左旋和右旋两种,和伸展树中的旋转相同,具体见。

红黑树的插入以及维护

    红黑树的插入和二叉查找树的插入相同,都是通过二叉树的性质找到待插入节点应该被插入的位置,然后插入。不过,由于红黑树具有之前提到的五点性质的要求,因此,还需要对红黑树进行额外的维护操作。

    插入之后,可能违反性质2、4,因此需要维护: 

(1)如果被插入的节点为根节点,则违反性质2,因此直接将 根节点的color改为BLACK即可 
(2)如果被插入的节点的父节点为黑色,则不违反任何规则,直接返回 
(3)如果被插入节点的父节点为红色,且祖父节点(肯定)为黑色,此时细分三种情况: 
* (a) 被插入节点的祖父节点的另一个子节点(即被插入节点的叔叔节点)为红色 
* (b) 被插入节点的叔叔节点为黑色,且被插入节点为其父节点的右子节点 
* (c) 被插入节点的叔叔节点为黑色,且被插入节点为其父节点的左子节点

对于(3.a),则

被插入节点的祖父节点的另一个子节点(即被插入节点的叔叔节点)为红色 

将当前节点的祖父节点改为红色,当前节点的父节点和叔叔节点改为黑色,同时当前节点设为其祖父节点,递归执行InsertFix

之前 

insert_3_1_bf 
之后 
insert_3_1_af

对于(3.b),则

被插入节点的叔叔节点为黑色,且被插入节点为其父节点的右子节点 

当前节点和其父节点执行左旋,父节点被旋转到下方,当前节点更新为下方的原父节点

之前 

insert_3_2_bf 
之后 
insert_3_2_af

对于(3.c),则

被插入节点的叔叔节点为黑色,且被插入节点为其父节点的左子节点 

父节点变为黑色,祖父节点变为红色,祖父节点和父节点进行右旋

之前 

insert_3_3_bf 
之后 
insert_3_3_af

这样经过以上的旋转染色操作,可以保证红黑树的性质2、4、5成立。

红黑树的删除与维护

    红黑树删除入和二叉查找树的删除相同,都是通过二叉树的性质找到待删除节点的位置,如果待删除节点没有子节点,则直接删除,并用空节点顶替该节点;如果待删除节点只有一个非空子节点,则用该非空子节点顶替待删除的节点;如果待删除节点两个节点均非空,则找到该节点的后继节点,交换该节点和其后继节点的数据,再次调用Delete操作。这样,再次调用后,找到原来节点的后继节点,此时该后继节点必定至多只有一个非空子节点,因此在前面所列举的情况下可以解决。 

    不过,由于红黑树具有之前提到的五点性质的要求,因此,还需要对红黑树进行额外的维护操作,维护操作从顶替被删除的节点的节点处开始。 
    如果被删除的节点为黑色,则删除之后,可能会违反红黑树的性质5,因此需要维护:设顶替被删除节点的节点为当前节点 
(1) 如果当前节点为红色,则直接将该节点变成黑色,返回即可 
(2) 如果当前节点是黑色,且为根节点,则直接返回即可 
(3) 如果当前节点为黑色,且非根节点,细分为如下四种情况: 
(a) 当前节点是黑色,且兄弟节点为红色(此时其父节点和兄弟节点的子节点必定为黑色) 
(b) 当前节点为黑色,且兄弟节点为黑色,且兄弟节点的两个子节点均为黑色 
(c) 当前节点为黑色,且兄弟节点是黑色,兄弟节点的左子结点为红色,右子节点为黑色 
(d) 当前节点为黑色,且兄弟节点为黑色,兄弟节点的右子节点为红色,兄弟节点的左子结点颜色任意

对于情形(3.a)

当前节点是黑色,且兄弟节点为红色(此时其父节点和兄弟节点的子节点必定为黑色), 则 

把父节点变成红色,兄弟节点变成黑色,然后对父节点和兄弟节点执行左或右旋操作,之后重新进入算法

之前 

delete_3_1_bf 
之后 
delete_3_1_af

对于情形(3.b)

当前节点是黑色,且兄弟节点为黑色,且兄弟节点的两个子节点全为黑色 

把当前节点的兄弟节点变成红色,然后当前节点变为其父节点

之前 

delete_3_2_bf 
之后 
delete_3_2_af 
由于被删除节点为黑色,此时当前节点的那条路径上的黑色节点的个数就减少1, 不满足性质5,此时将当前节点的兄弟节点染成红色,当前节点提升为其父节点。此时,从当前节点向下的路径上,黑色节点的个数相同,但是和从更高节点到叶节点的路径相比,黑色节点个数仍然少1.

对于情形(3.c)

当前节点为黑色,且兄弟节点是黑色,兄弟节点的左子结点为红色,右子节点为黑色 

把兄弟节点变成红色,兄弟节点的左子结点变成黑色,然后对兄弟节点及其左子结点执行右旋操作

之前 

delete_3_3_bf 
之后 
delete_3_3_af

对于情形(3.d)

当前节点为黑色,且兄弟节点为黑色,兄弟节点的右子节点为红色,兄弟节点的左子结点颜色任意 把兄弟节点染成当前节点父节点的颜色,把当前节点父节点染成黑色,兄弟节点右子节点染成黑色,之后对当前节点父节点执行左旋操作

之前 

delete_3_4_bf 
之后 
delete_3_4_af

实现(伪码)

RB-INSERT-FIXUP(T, z)      while z.p.color == RED          do if z.p == z.p.p.left              then y ← z.p.p.right              if y.color == RED                  then z.p.color ← BLACK               ▹ Case 1                  y.color ← BLACK                    ▹ Case 1                  z.p.p.color ← RED                    ▹ Case 1                  z ← z.p.p                            ▹ Case 1              else if z == z.p.right                  then z ← z.p                          ▹ Case 2                  LEFT-ROTATE(T, z)                   ▹ Case 2              z.p.color ← BLACK                        ▹ Case 3              z.p.p.color ← RED                         ▹ Case 3              RIGHT-ROTATE(T, z.p.p)                  ▹ Case 3          else (same as then clause with "right" and "left" exchanged)      T.root.color ← BLACK  while x ≠ root[T] and color[x] = BLACK          do if x = left[p[x]]                then w ← right[p[x]]                     if color[w] = RED                       then color[w] ← BLACK                        ▹  Case 1                             color[p[x]] ← RED                       ▹  Case 1                             LEFT-ROTATE(T, p[x])                    ▹  Case 1                             w ← right[p[x]]                         ▹  Case 1                     if color[left[w]] = BLACK and color[right[w]] = BLACK                       then color[w] ← RED                          ▹  Case 2                            x ← p[x]                                ▹  Case 2                       else if color[right[w]] = BLACK                               then color[left[w]] ← BLACK          ▹  Case 3                                    color[w] ← RED                  ▹  Case 3                                    RIGHT-ROTATE(T, w)              ▹  Case 3                                    w ← right[p[x]]                 ▹  Case 3                             color[w] ← color[p[x]]                 ▹  Case 4                             color[p[x]] ← BLACK                    ▹  Case 4                             color[right[w]] ← BLACK                ▹  Case 4                             LEFT-ROTATE(T, p[x])                   ▹  Case 4                             x ← root[T]                            ▹  Case 4            else (same as then clause with "right" and "left" exchanged)    color[x] ← BLACK

 


和AVL比较

    红黑树并不追求“完全平衡”——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。 

    红黑树能够以O(log2n) 的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高。

参考:

转载地址:http://rembx.baihongyu.com/

你可能感兴趣的文章
将txt文件转化为json进行操作
查看>>
线性表4 - 数据结构和算法09
查看>>
C语言数据类型char
查看>>
Online Patching--EBS R12.2最大的改进
查看>>
Binary Search Tree Iterator leetcode
查看>>
Oracle性能优化--DBMS_PROFILER
查看>>
uva-317-找规律
查看>>
Event事件的兼容性(转)
查看>>
我的2014-相对奢侈的生活
查看>>
zoj 2412 dfs 求连通分量的个数
查看>>
Java设计模式
查看>>
一文读懂 AOP | 你想要的最全面 AOP 方法探讨
查看>>
Spring Cloud 微服务分布式链路跟踪 Sleuth 与 Zipkin
查看>>
ORM数据库框架 SQLite 常用数据库框架比较 MD
查看>>
华为OJ 名字美丽度
查看>>
微信公众号与APP微信第三方登录账号打通
查看>>
onchange()事件的应用
查看>>
Windows 下最佳的 C++ 开发的 IDE 是什么?
查看>>
软件工程师成长为架构师必备的十项技能
查看>>
python 异常
查看>>