您的位置:首页 > 其它

《算法导论》读书笔记——红黑树(Red Black Tree)【for_wind】

2013-01-03 17:51 351 查看
//好久没有写博文了,看过的书,做过的思考还是需要记录。--for_wind

【置顶】

1、PPT总结:

(已经更新,不用资源分下载了,上面详细地解释了红黑树的算法,建议幻灯片看哦,当年写了好久阿)

http://download.csdn.net/detail/for_wind/7325727

2、具体代码:

(很久以前写的,现在放到github上了,仅供参考)

https://github.com/forwind/RedBlackTree


------------建议直接查看上面的PPT,以下为资料整理备份----------------------

红黑树是一种接近平衡的二叉查找树。

简介与性质:

红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。

满足以下5条性质:

1、每个节点或是红,或是黑;

2、根节点是黑的;

3、每个叶子节点是黑的;

4、如果一个节点是红的,则其两个儿子节点都是黑的;

5、对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑节点。

必须牢记:在红黑树上的几个操作(旋转、插入、删除)结束后,形成的新树必须依旧保持5条红黑性质

引理:

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

以上引理能很好地说明为何红黑树是一种好的查找树。

几点疑惑:

为何只要同时满足红黑树的这些条件,就一定会有“红黑树可以保证任何两条从根部到树叶的路径节点个数相差不超过2倍”这个平衡的性质?

假设,如果存在两条路径L和S,L比S长两倍以上(S路径上有n个节点,L上有大于2n个节点)。可知,S的黑高度最大只可能是n,那么根据第5条性质,L的黑高度也大也只可能是n,也就是,L路径上一定有超过n个红色节点(因为节点不是黑的就必定是红的)。所以,肯定会有两个以上的红色节点是相邻的。这就与第4个条件矛盾了。所以,红黑树可以保证任何两条从根部到树叶的路径节点个数相差不超过2倍。
红黑树和二叉查找树的关系如何?性能方面

由12章我们知道,二叉查找树上执行的基本动态集合操作(查找、插入、删除等)的时间是与树的高度成正比的。我们总是奢望这棵树的高度尽可能地降低,其各子树的规模尽可能地平均。最理想的情况形成完全二叉树:θ(lgn),最坏的情况:具有n个结点的线性链:O(n)。对于随机化构造来说,平均时间为θ(lgn),但是实际中,并不总能保证二叉查找树是随机构造成的。

红黑树通过其特别的节点着色方式的限制,让树尽可能平衡。由引理可知,红黑树能保证在最坏情况下,基本的动态集合操作的时间均为O(lgn)。红黑树是一种接近平衡的二叉查找树。

算法分析

本文总结了理解算法中可能会出现的疑惑。关于代码,我实现了C++版本的,如有需要,请留言。

简介

那么红黑树具体是如何实现的呢?

红黑树的查找、最大值、最小值、前趋、后继等操作,与普通的二叉搜索树没有什么区别。插入和删除操作需要重新实现。仅仅用普通的二叉搜索树的插入和删除动作,可能会破坏红黑树本身的一些性质,因此,需要进行额外的处理。这些额外的处理主要是修改某些节点颜色、修改指针结构。

旋转

指针结构的修改是通过旋转来完成的,这是一种能保持二叉查找树性质的查找树局部操作。共有两种:左旋,右旋。

理解要点:保持其性质(若改变了二叉查找树的性质,则结果是无意义的);局部(参与的节点数目为2到5)。

插入

向红黑树插入节点,先将需要插入的节点设为红色,用普通二叉搜索树的方法将这个节点插入到树中,然后再想办法把被破坏的红黑性质恢复。
为何将新插入点设为红色?

插入黑点,会增加路径上黑点的数目,一定会破坏性质5

插入红点,

当其父节点为黑色时,不影响平衡,继续保持红黑性质

当其父节点为红色时,可能破坏性质2(根节点是黑色的)、性质4(红色节点的子节点一定是黑色节点),需要进行修正。

更多更好的解释,来自 ,详见本文最后部分。
Case 1下,为何设置z=p[p[z]](ptrZ=ptrZ->parent->parent)并继续循环迭代?(P167 上伪代码RB_INSERT_FIXUP(T,z)中第8行、第2行)

因为p[p[z]](ptrZ->parent->parent)被设置为红色后,

当p[p[z]](ptrZ->parent->parent->parent)为红色(即新的红Z的父节点可能为红色)时,

符合case 1,仍旧破坏性质4(如果一个节点是红的,则其两个儿子节点都是黑的),因而执行上述操作循环修正。
通过左旋,右旋,以及恰当的颜色重设,能够有效继续保持性质5,进而将破坏的性质4修正

理解这一点非常重要。性质4(如果一个节点是红的,则其两个儿子节点都是黑的)在情况1,2,3中被破坏的原因是因为z和其父节点都是红色的。在恢复性质4的过程中,采用的操作可以破坏性质2,4,但是避免破坏性质5。因为性质5(对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑节点)破坏后更难恢复。

删除

详见摘录。

参考

以下摘录来着精彩分析:

为何将新插入点设为红色?关于红黑树插入节点的算法理解

博文地址:http://liyiwen.iteye.com/blog/345800 

将新插入的节点颜色设为红色,以尽量减少对红黑性质的破坏,红黑性质恢复起来也更快。插入红色节点,被破坏的部分会在局部,考虑的问题也就比较少,恢复过程也容易形成递归。

我们考虑下,如果一个红色节点(下文称用Z指向它)被插入到树中,那么有哪些红黑性质可能被破坏呢?只有第2条(根节点是黑色的)以及第4条(红色节点的子节点一定是黑色节点),其它都不会被破坏。

如果插入的节点的父节点是黑色的,那么不需要做任何调整,这红黑树是正常的。如果父节点是红色,或没有父节点(也就是插在了树根的位置),那么就要进行调整以保证红黑树是正确的。

首先对第4 条进行分析,我们知道,插入一个新的节点,这个节点肯定会被放到树的底部成为一个叶节点(参考普通二叉树的插入过程),那么这个红色节点就没有可能和自己的子节点同色(因为叶节点的子节点是NIL节点,都是黑色的),如果第4条被破坏的话,肯定是Z指向的节点的父节点是红色的。因此,为了使分析和解决更加容易和清晰,我们在对树进行调整以恢复红黑特性时,始终使得Z总是指向相邻红色的节点中的子节点(指针Z可能会向上升到树的中部或根部)。基于这个做法,我们可以知道,如果是第2条被破坏了的话,也就是Z指向根节点了,那么第4条肯定就符合了(因为Z的父节点是NIL,黑色的),因此对第2条性质的恢复变得很简单,只需要被根从红色变为黑色即可。这时,所有性质都会被满足了(因为是根节点,所以根节点被着为黑色时,所有路径都黑高会统一加1,也就是第5条不会被破坏,操作之后的红黑树仍然是正确的)。好了,现在只留下第4条性质的恢复的问题了。

如果第4条被破坏了,也就是说,Z的父节点是红色的,那么,说明,Z一定有祖父节点,而且是黑色的(否则插入前原树就有问题,又或是调整时的方法不正确)。因此可以把问题放到以Z的祖父节点为根节点的子树内进行解决,这样可以把调整的范围最小化,而且这也是有可能的:只要不改变这子树的黑高度,那么就不会对树的其它部分产生影响。我们要做的就是在这个子树范围内把红黑性质调整回来。再看子树的根是否与其父节点同为红色,是的话,就再次用前面所说的去解决它,一直向上递归到红黑性质被恢复为止。
关于红黑树删除节点的算法理解

博文地址:http://liyiwen.iteye.com/blog/345799

现在我们来看红黑性质的恢复过程:

如果Y指向的节点是个红色节点,那么直接删除掉Y以后,红黑性质不会被破坏。操作结束。
如果Y指向的节点是个黑色节点,那么就有几条红黑性质可能受到破坏了。

首先是包含Y节点的所有路径,黑高度都减少了1(第5条被破坏)。其次,如果Y的有红色子节点,Y又有红色的父节点,那么Y被删除后,就出现了两个相邻的红色节点(第4条被破坏)。最后,如果Y指向的是根节点,而Y的子节点又是红色的,那么Y被删除后,根节点就变成红色的了(第2条被破坏)。

其中,第5条被破坏是让我们比较难受的。因为这影响到了全局。这样动作就太大太复杂了。而且在这个条件下,进行其它红黑性质的恢复也很困难。所以我们首先解决这个问题:如果不改变含Y路径的黑高度,那么树的其它部分的黑高度就必须做出相应的变化来适应它。所以,我们想办法恢复原来含Y节点的路径的黑高度。做法就是把Y节点的黑色,推到它的子节点X上去。(X可能是NIL节点)。这样,X就可能具有双重黑色,或是同时具有红黑两色,也就是第1条性质被破坏了。

但第1条性质是比较容易恢复的:一、如果X是同时具有红黑两色,那么好办,直接把X涂成黑色,就行了。而且这样把所有问题都解决了。因为将X变为黑色,如果2、4两条性质有问题的话也会得到恢复。二、如果X是双黑色,那么我们希望把这种情况向上推,一直推到根节点(调整树结构和颜色,X的指向新的双黑色节点,X不断向上移动),让根节点具双黑色,这时,直接把X的一层黑色去掉就行了(因为根节点被包含在所有的路径上,所以这样做所有路径同时黑高减少1,不会破坏红黑特征)。

下面就具体地分析如何恢复1、2、4三条可能被破坏的红黑特性:我们知道,如果X指向的节点是有红黑两色,或是X是根节点时,只需要简单的对X进行一些改变就行了。要对除X节点外的其它节点进行操作时,必定是这样的情况:X节点是双层黑色,且X有父节点P。由知可知,X必然有兄弟节点W,而且这个W节点必定有两个子节点。(因为这是原树满足红黑条件要求而自然具备的。X为双黑色,那么P的另一个子节点以下一定要有至少两层的节点,否则高黑度不可能和X路径一致)。所以我们就分析这些节点之间如何变形,把问题限制在比较小的范围内解决。另一个前提是:X在一开始,肯定是树底的叶节点或是NIL节点,所以在递归向上的过程中,每一步都保证下一步进行时,至少
X的子树是满足红黑特性的。因此子树的情况就可以认为是已经正确的了,这样,分析就只限制在X节点,X的父节点P,X的兄弟节点W,以及W的两个子节点。这些个节点中。

本文的最后再推荐个关于红黑树算法的文章:

《教你透彻了解红黑树》http://blog.csdn.net/v_july_v/article/details/6105630
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息