教你透彻了解红黑树

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
...全文
1047 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
  • 打赏
  • 举报
回复
学习了 ..
红黑树的c实现源码与剖析 原作者:那谁 源码剖析作者:July ===================== July说明: 由于原来的程序没有任何一行注释,我把它深入剖析,并一行一行的添加了注释, 详情请参见此文: 你彻底实现红黑树红黑树的c源码实现与剖析 http://blog.csdn.net/v_JULY_v/archive/2011/01/03/6114226.aspx 关于红黑树系列的程,还可看下以下倆篇文章: 透彻了解红黑树: http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx 红黑树算法的层层剖析与逐步实现 http://blog.csdn.net/v_JULY_v/archive/2010/12/31/6109153.aspx Ok,君自看。 -------------------------------------------------------------------------------------------------- //以下是最初的源程序。 //如果你看不太懂,那么就证明了我所做的源码剖析工作有意义了。:D。 //详情,参见My Blog[谷歌或百度搜"结构之法"] //http://blog.csdn.net/v_JULY_v ------------------------------------------------------------------------------------------------- #include #include #include ............. .............. //:D。这下,你应该发现我所添加的注释的价值了。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/v_JULY_v/archive/2011/01/03/6114226.aspx 一切的详情请参见此文: 你彻底实现红黑树红黑树的c源码实现与剖析 http://blog.csdn.net/v_JULY_v/archive/2011/01/03/6114226.aspx 关于红黑树系列的程,还可看下以下倆篇文章: 透彻了解红黑树: http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx 红黑树算法的层层剖析与逐步实现 http://blog.csdn.net/v_JULY_v/archive/2010/12/31/6109153.aspx 我博客里还有有关微软等公司数据结构+算法面试100题的资料, 详情,参见My Blog: http://blog.csdn.net/v_JULY_v ----- July、二零一一年一月三日。
前言: 本人的原创作品经典算法研究系列,自从10年12月末至11年12月,写了近一年。可以这么说,开博头俩个月一直在整理微软等公司的面试题,而后的四个月至今,则断断续续,除了继续微软面试100题系列,和程序员编程艺术系列之外,便在写这经典算法研究系列和相关算法文章。 本经典算法研究系列,涵盖A*.Dijkstra.DP.BFS/DFS.红黑树.KMP.遗传.启发式搜索.图像特征提取SIFT.傅立叶变换.Hash.快速排序.SPFA.快递选择SELECT等15个经典基础算法,共计31篇文章,包括算法理论的研究与阐述,及其编程的具体实现。很多个算法都后续写了续集,如第二个算法:Dijkstra 算法,便写了4篇文章;sift算法包括其编译及实现,写了5篇文章;而红黑树系列,则更是最后写了6篇文章,成为了国内最为经典的红黑树程。 OK,任何人有任何问题,欢迎随时在blog上留言评论,或来信:zhoulei0907@yahoo.cn批评指正。谢谢。以下是已经写了的15个经典算法集锦,算是一个目录+索引,共计31篇文章: 十五个经典算法研究集锦+目录 一、A*搜索算法 一(续)、A*,Dijkstra,BFS算法性能比较及A*算法的应用 二、Dijkstra 算法初探 二(续)、彻底理解Dijkstra算法 二(再续)、Dijkstra 算法+fibonacci堆的逐步c实现 二(三续)、Dijkstra 算法+Heap堆的完整c实现源码 三、动态规划算法 四、BFS和DFS优先搜索算法 五、透彻了解红黑树 (红黑数系列六篇文章之其中两篇) 五(续)、红黑树算法的实现与剖析 六、你初步了解KMP算法、updated (KMP算法系列三篇文章) 六(续)、从KMP算法一步一步谈到BM算法 六(三续)、KMP算法之总结篇(必懂KMP) 七、遗传算法 透析GA本质 八、再谈启发式搜索算法 九、图像特征提取与匹配之SIFT算法 (SIFT算法系列五篇文章) 九(续)、sift算法的编译与实现 九(再续)、你一步一步用c语言实现sift算法、上 九(再续)、你一步一步用c语言实现sift算法、下 九(三续):SIFT算法的应用--目标识别之Bag-of-words模型 十、从头到尾彻底理解傅里叶变换算法、上 十、从头到尾彻底理解傅里叶变换算法、下 十一、从头到尾彻底解析Hash表算法 十一(续)、倒排索引关键词Hash不重复编码实践 十二、快速排序算法 (快速排序算法3篇文章) 十二(续)、快速排序算法的深入分析 十二(再续):快速排序算法之所有版本的c/c++实现 十三、通过浙大上机复试试题学SPFA 算法 十四、快速选择SELECT算法的深入分析与实现 十五、多项式乘法与快速傅里叶变换

70,037

社区成员

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

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