教你透彻了解红黑树

v_JULY_v
博客专家认证
2010-12-29 07:13:14
教你透彻了解红黑树


作者 July 2010年12月29日
------------------
本文参考:Google、算法导论、STL源码剖析、计算机程序设计艺术。
本人声明:个人原创,转载请注明出处。

一、红黑树的介绍
先来看下算法导论对R-B Tree的介绍:
红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。
通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。

前面说了,红黑树,是一种二叉查找树,既然是二叉查找树,那么它必满足二叉查找树的一般性质。
下面,再具体介绍红黑树之前,咱们先来了解下 二叉查找树的一般性质:
1.在一棵二叉查找树上,执行查找、插入、删除等操作,的时间复杂度为O(lgn)。
因为,一棵由n个结点,随机构造的二叉查找树的高度为O(lgn),所以顺理成章,一般操作的执行时间为O(lgn)。
(至于n个结点的二叉树高度为O(lgn)的证明,可参考算法导论 第12章 二叉查找树。)
2.但若是一棵具有n个结点的线性链,则此些操作最坏情况运行时间为O(n)。

而红黑树,能保证在最坏情况下,基本的动态几何操作的时间均为O(lgn)。
ok,我们知道,红黑树上每个结点内含五个域,color,key,left,right。如果相应的指针域没有,则设为NIL。

一般的,红黑树,满足一下性质,即只有满足一下性质的树,我们才称之为红黑树:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

下图所示,即是一颗红黑树:

此图忽略了叶子和根部的父结点。总之,可以这样表示,就对了。:D。

..........

红黑树插入、删除操作的具体实现
ok,接下来,咱们来具体了解红黑树的插入操作。
向一棵含有n个结点的红黑树插入一个新结点的操作可以在O(lgn)时间内完成。

算法导论:
RB-INSERT(T, z)
1 y ← nil[T]
2 x ← root[T]
3 while x ≠ nil[T]
4 do y ← x
5 if key[z] < key[x]
6 then x ← left[x]
7 else x ← right[x]
8 p[z] ← y
9 if y = nil[T]
10 then root[T] ← z
11 else if key[z] < key[y]
12 then left[y] ← z
13 else right[y] ← z
14 left[z] ← nil[T]
15 right[z] ← nil[T]
16 color[z] ← RED
17 RB-INSERT-FIXUP(T, z)

咱们来具体分析下,此段代码:
RB-INSERT(T, z),将z插入红黑树T 之内。

为保证红黑性质在插入操作后依然保持,上述代码调用了一个辅助程序RB-INSERT-FIXUP
来对结点进行重新着色,并旋转。

14 left[z] ← nil[T]
15 right[z] ← nil[T] //保持正确的树结构
第16行,将z着为红色,由于将z着为红色可能会违背某一条红黑树的性质,
所以,在第17行,调用RB-INSERT-FIXUP(T,z)来保持红黑树的性质。

RB-INSERT-FIXUP(T, z),如下所示:
1 while color[p[z]] = RED
2 do if p[z] = left[p[p[z]]]
3 then y ← right[p[p[z]]]
4 if color[y] = RED
5 then color[p[z]] ← BLACK ▹ Case 1
6 color[y] ← BLACK ▹ Case 1
7 color[p[p[z]]] ← RED ▹ Case 1
8 z ← p[p[z]] ▹ Case 1
9 else if z = right[p[z]]
10 then z ← p[z] ▹ Case 2
11 LEFT-ROTATE(T, z) ▹ Case 2
12 color[p[z]] ← BLACK ▹ Case 3
13 color[p[p[z]]] ← RED ▹ Case 3
14 RIGHT-ROTATE(T, p[p[z]]) ▹ Case 3
15 else (same as then clause
with "right" and "left" exchanged)
16 color[root[T]] ← BLACK


ok,参考一网友的言论,用自己的语言,再来具体解剖下上述俩段代码。
为了保证阐述清晰,我再写下红黑树的5个性质:

1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

在对红黑树进行插入操作时,我们一般总是插入红色的结点,因为这样可以在插入过程中尽量避免对树的调整。
那么,我们插入一个结点后,可能会使原树的哪些性质改变列?
由于,我们是按照二叉树的方式进行插入,因此元素的搜索性质不会改变。

如果插入的结点是根结点,性质2会被破坏,如果插入结点的父结点是红色,则会破坏性质4。
因此,总而言之,插入一个红色结点只会破坏性质2或性质4。
我们的回复策略很简单,
其一、把出现违背红黑树性质的结点向上移,如果能移到根结点,那么很容易就能通过直接修改根结点来恢复红黑树的性质。直接通过修改根结点来恢复红黑树应满足的性质。
其二、穷举所有的可能性,之后把能归于同一类方法处理的归为同一类,不能直接处理的化归到下面的几种情况,

情况1:插入的是根结点。
原树是空树,此情况只会违反性质2。
对策:直接把此结点涂为黑色。
情况2:插入的结点的父结点是黑色。
此不会违反性质2和性质4,红黑树没有被破坏。
对策:什么也不做。
情况3:当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色。
此时父结点的父结点一定存在,否则插入前就已不是红黑树。
与此同时,又分为父结点是祖父结点的左子还是右子,对于对称性,我们只要解开一个方向就可以了。

在此,我们只考虑父结点为祖父左子的情况。
同时,还可以分为当前结点是其父结点的左子还是右子,但是处理方式是一样的。我们将此归为同一类。
对策:将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点,从新的当前节点重新开始算法。

针对情况3,变化前:
...........

===========
更多请参考:
http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx
详情,参见My BLog:
http://blog.csdn.net/v_JULY_v
...全文
927 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
v_JULY_v 2010-12-30
  • 打赏
  • 举报
回复
[Quote=引用楼主 v_july_v 的回复:]
教你透彻了解红黑树


作者 July 2010年12月29日
------------------
本文参考:Google、算法导论、STL源码剖析、计算机程序设计艺术。
本人声明:个人原创,转载请注明出处。

一、红黑树的介绍
先来看下算法导论对R-B Tree的介绍:
红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。
通过……
[/Quote]

红黑树的删除部分,图,已经全部补充完整,大功告成。:D。
ouyh12345 2010-12-30
  • 打赏
  • 举报
回复
lastrobber 2010-12-30
  • 打赏
  • 举报
回复
这算法,没敲过,只敲了敲霍夫曼树的说。。。
forest_xi 2010-12-30
  • 打赏
  • 举报
回复
学习ing
sparklxd 2010-12-30
  • 打赏
  • 举报
回复
先顶再看
xpston008 2010-12-30
  • 打赏
  • 举报
回复
刚看stl源码分析。弱弱的学习下先
昵称很不好取 2010-12-30
  • 打赏
  • 举报
回复
又见楼主大作~~
jianwei824 2010-12-30
  • 打赏
  • 举报
回复
学习啊,楼主是算法大儒啊
  • 打赏
  • 举报
回复
很好,强烈支持。
SENSSSZ 2010-12-30
  • 打赏
  • 举报
回复
很好,强烈支持。
naturemickey 2010-12-29
  • 打赏
  • 举报
回复
很好。
漫步者、 2010-12-29
  • 打赏
  • 举报
回复
搞得我不知道说什么好了。
wasx1 2010-12-29
  • 打赏
  • 举报
回复
嗯,谢谢楼主啦
吴明治 2010-12-29
  • 打赏
  • 举报
回复
有时间写一写。
liutengfeigo 2010-12-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 mylanyuer 的回复:]

很好,学习,像平衡二叉树
[/Quote]
我老师讲平衡二叉树的时候直接跳过了。
liutengfeigo 2010-12-29
  • 打赏
  • 举报
回复
自己不去实现一遍,反正是不会明白的。
月中蓝 2010-12-29
  • 打赏
  • 举报
回复
很好,学习,像平衡二叉树
qq120848369 2010-12-29
  • 打赏
  • 举报
回复
俺连照着算法导论敲一遍的勇气都没有,膜拜.,
AAA20090987 2010-12-29
  • 打赏
  • 举报
回复
菜鸟来学习了
yuppy 2010-12-29
  • 打赏
  • 举报
回复
学习了 ..

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧