红黑树(Red-Black Tree)是二叉搜索树(Binary Search Tree)的一种改进。二叉查找树在最坏情况下可能会变成一个链表(从小到大插入时)。而红黑书每次插入或删除后都会用O(logN)的时间来修改树的结构以保持平衡。</span>
红黑树另一个优点是:除了删除和插入以外,二叉查找树中的查找最大键,查找最小键,查找小于当前键的元素数量,查找某一个键 等算法不用任何修改就可以直接在红黑树中使用。
红黑树的结点额外添加了一个属性为:颜色,分为红色和黑色。可以认为红色结点与其父结点(黑色)可以构成一颗3-树(即有两个键和三条链接的树)。
----------------------------------
引言:
作者本来想实现一下红黑树,网上搜了以后发现了一篇不错的文章http://blog.youkuaiyun.com/v_JULY_v/article/details/6109153
但是作者在“红黑树的插入和删除结点的全程演示”中所用到的方法和实现与剖析中所用到的方法并不一样。
而我找到了一种更简单的删除算法:http://gengning938.blog.163.com/blog/static/1282253812011420103852696/
但是此处只有图片和文字,没有代码实现,于是打算结合两者的优点,代码主体使用的是v_JULY_v的,但是删除算法用的是枫叶大哥的。
----------------------------------
正文:
红黑树的四条性质:
1:根结点是黑色的。
2:空结点是黑色的。
3:一条连接不能同时链接两个红色结点。
4:从根节点到任何外部节点(叶子节点)路径上经过的黑色结点数目是相同的。
而这些性质约束了红黑树从根到叶子节点的路径最多不超过最短可能路径的两倍长。因为红黑树不是绝对平衡的,但可以认为是黑色绝对平衡的。
将红色结点与其父结点之间的链接画平,可以直观看出上述结论。
由于删除和插入都要用到一种叫做左旋和右旋的方法,所以我们先介绍一下左旋和右旋:
如上图是以x为枢轴点左旋(从左图->右图)和以y轴为枢轴点右旋(右图->左图)。
实现比较简单:右旋为例:
y的左链接指向β,x的又链接指向y,y的父链接的左或者右(取决于y在哪边)链接指向x。
左旋的话,上述左和右颠倒就可以。
左旋、右旋都是对称的,且都是在O(1)时间内完成。因为旋转时只有指针被改变。
红黑树的插入算法实现:
接下来把z的颜色设成红色。为什么?还记得红黑树的性质吗,从根节点向下到空节点的每一条路径上的黑色节点数要相同。如果新插入的是黑色节点,那么它所在的路径上就多出了一个黑色的节点了。所以新插入的节点一定要设成红色。但是这样可能又有一个矛盾,如果z的父节点也是红色,怎么办,前面说过红色节点的子节点必须是黑色。因此我们要执行下面一个迭代的过程,称为InsertFixup,来修补这棵红黑树。
情况1


情况2:

情况3

红黑树的删除:
一些隐藏知识点:
遇到节点先判断是否有两个子结点,如果有就查找右子树中最小值进行替换。没有两个子结点就跳过替换。
经过上一步以后,要删除的点变为以下情况:
不可能还有两个子节点。
如果有一个子结点的话,那么该节点肯定为右结点,且要删除的节点肯定为黑色,而右结点肯定为红色。
如果无子节点的话,则删除结点可能为红色,可能为黑色。
删除结点首先要按二叉查找树删除结点的算法进行
一、普通二叉查找树删除一个结点:
(1)待删除结点没有子结点,即它是一个叶子结点,此时直接删除
(2)待删除结点只有一个子结点,则可以直接删除;如果待删除结点是根结点,则它的子结点变为根结点;如果待删除结点不是根结点,则用它的子结点替代它的位置。
(3)待删除结点有两个子结点,首先找出该结点的后继结点(即右子树中数值最小的那个结点),然后将两个结点进行值交换(即:只交换两个结点的数值,不改变结点的颜色)并将待删除结点删除,由于后继结点不可能有左子结点,对调后的待删除结点也不会有左子结点,因此要把它删除的操作会落入情况(1)或情况(2)中。
二、.红黑树的删除结点算法
1.待删除结点有两个外部结点,操作如下:
(1)直接把该结点调整为叶结点
(2)若该结点是红色,则可直接删除,不影响红黑树的性质,算法结束
(3)若该结点是黑色,则删除后红黑树不平衡。此时要进行“双黑”操作
记该结点为V,则删除了V后,从根结点到V的所有子孙叶结点的路径将会比树中其他的从根结点到叶结点的路径拥有更少的黑色结点, 破坏了红黑树性质4。此时,用“双黑”结点来表示从根结点到这个“双黑”结点的所有子孙叶结点的路径上都缺少一个黑色结点。
双黑含义:该结点需要代表两个黑色结点,才能维持树的平衡
图1