红黑树为什么要有 nil节点_5分钟深入理解红黑树(图文详解)

红黑树是平衡树的一种,保证最坏情况下操作时间复杂度为O(lgo(n))。红黑树的应用比较广泛,比如作为C++中STL的set和map的底层数据结构,Java集合中TreeSet和TreeMap的底层数据结构等。学习红黑树,可以把二叉查找树作为参考,这样有助于加深理解。红黑树的操作主要包括节点旋转、插入、删除等操作,下面咱们就一一来看:

1、红黑树性质

  1. 每个节点是红色的,或者是黑色的
  2. 根节点是黑色的
  3. 每个叶节点(nil)是黑色的
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的
  5. 对每个节点,从该节点到其后代叶节点的简单路径上,均包含相同数目的黑色节点

红黑树整体节点图示如下:

6ecc7983508b7381207979637c44ed08.png

2、旋转

旋转是保持二叉搜索树(红黑树)局部性质的操作,包括左旋和右旋。当在节点x上做左旋时,假设它的右孩子为y而不是T.nil,X可为其右孩子不是T.nil的任何节点,同理,X做右旋也是一样的。

bd2791742fe0d37182ad1a57b2e3ee0a.png

伪代码如下(左旋)

a2a167791c5333ab0eab495bafbc321f.png

左旋Java示例代码:

/** * 左旋操作 */private void leftRotate(Node x) { Node y = x.right; x.right = y.left; if (y.left != nil) { y.left.parent = x; } y.parent = x.parent; if (x.parent == nil) { root = y; } else if (x == x.parent.left) { x.parent.left = y; } else { x.parent.right = y; }  x.parent = y; y.left = x;}

3、插入

在O(log(n))时间内插入一个节点,RB-INSERT过程完成该操作,像一个普通的二叉搜索树插入操作一样,然后将要插入的节点Z着为红色。为了保持红黑树的性质,调用一个辅助函数RB-INSERT-FIXUP来对节点重新着色并旋转。待插入节点Z已保存了数据项。

584da043729df3e4adf6561defd825fb.png

RB-INSERT-FIXUP过程伪代码

bc766de26af78524eaaacc08387ddc6c.png
2457b20bcec934c68d922f8e2c46a456.png

注意:Case1属于if判断条件,Case2和Case3属于else语句,Case2是else语句中的if判断语句的。具体可以看代码。

插入过程Java代码示例:

/** * 往红黑树中插入一个元素 * @param data */public void insert(int data) { Node y = nil; Node x = root;  if (root == nil) { root = newNode(data); root.color = Node.BLACK; } else { while (x != nil) { if (data < x.data) { y = x; x = x.left; } else if (data > x.data) { y = x; x = x.right; } else { return; } }  Node z = newNode(data); z.parent = y; if (data < y.data) { y.left = z; } else { y.right = z; } if (y.color == Node.RED) { insertFixup(z); } }}

RB-INSERT-FIXUP过程分析

第1-15行的while循环在每次迭代的开始始终保持以下3个条件是不变的

  1. 节点z是红节点
  2. 如果z.p是根节点,则z.p是黑节点
  3. 如果有任何红黑树性质贝破坏,则至多有一条被破坏,或是性质2,或是性质4(各个性质见红黑树性质总结)。如果性质2被破坏,则因为z是根节点且是红节点。性质4被破坏则是因为z和z.p都是红节点。

循环终止条件:

循环终止因为z.p是黑色的(如果z是根节点,则z.p是黑色哨兵节点),这样,在循环终止时并没有违反性质4,唯一可能不成立的就是性质2,不过第16行(伪代码中的行)恢复了这个性质。

循环保持条件:

循环保持有6中条件,其中3种和另外3种是对称的,这取决于z的父节点z.p是z的祖父节点z.p.p的左孩子还是右孩子。情况1、2、3的区别就在于z 的父节点的兄弟节点(z的叔节点)的颜色不同,加入y指向z的叔节点,如果y的颜色是红色的,则执行情况1,否则转向情况2和3。在所有的3种情况中,z 的祖父节点z.p.p是黑色的,因为他的父节点z.p是红色的,故性质4只有在z和z.p之间被破坏了。

d60bd9e47345f0215ce72923d66dc620.png

情况1:z的叔节点y是红色的

此时对应Case1,将z.p和y都着成黑色,解决z和z.p都是红色的问题,将z.p.p着成红色保持性质5,然后把z.p.p作为新节点z来继续进行while循环,指针z上移两层

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值