平衡二叉查找树:红黑树

平衡二叉查找树:红黑树

                                                                                                                                                                                                                                                                原文链接

红黑树的定义

    红黑树是满足如下条件的二叉树:

(1)每个结点都有颜色标记,要么是黑色,要么是红色

(2)根结点是黑色的

(3)叶子结点是黑色的(按《算法导论》和其他文献的说法是,这里的叶子结点指的是空结点)

(4)红色结点的孩子必须是黑色的

(5)从根结点到每一个叶子结点的路径上,黑色结点的个数相同。(有部分文献里“根结点”说成“任意结点”,其实这种说法是一样的,因为任意子树也是一颗二叉树,如果它的根是黑色的,那么它本身也是一颗红黑树,如果它的根是红色的,由于它属于红黑树的一部分,而它的对于“黑色结点的个数”没有贡献,因此它到它的叶子结点路径上的黑色个数也必然是相同的)

注:以上5个性质在插入、删除的过程是时刻要维护的。

红黑树比朴素二叉查找树效率更高的原因

    红黑树的查找、插入、删除操作都可以在最坏情况下保持为O(log2N),其中N为树的结点个数。而朴素二叉查找树则在最坏情况下为O(N)。其实,红黑树并非严格意义上的高平衡度的平衡二叉树,它之所以能够维持高效,是根据它的定义内容来实现的。假设红黑树的高为H,结点数为N,则根据(4)可以知道,在一颗红黑树中,黑色结点的高度至少为H/2,则可以得到这样的一个不等式:

    2H/2 - 1 <= N(高度为H/2的二叉树中结点个树最多为 2H/2 - 1)

    原公式可以化为H <= 2*log2(N+1),从而可以知道红黑树的高度最多为近似log2N的两倍。忽略常数,红黑树的所有操作便是O(log2N)

二叉树中的旋转操作

    旋转操作是调整二叉树结构的一种方法,通过旋转,该二叉树的中序遍历序列不变。主要有两个方向的旋转。用圆形代表结点,矩形代表一颗子树。

右旋:

根据图可以看出,右旋其实就是把B的右孩子作为A的左孩子,再将B作为根,其右孩子为A。

左旋:

 左旋其实就是右旋的镜像,把B的左孩子作为A的右孩子,将B作为根,其左孩子为A。

注:红黑树维持其结构性质的过程中,需要用到上述旋转操作。

红黑树的插入操作

    红黑树的插入跟普通二叉查找树的插入是一样的,但是插入过程中很容易就会破坏红黑树的结构。维护红黑树的结构就是要保证其5个性质一直得以保持。

    首先,规定新插入的结点的颜色是红色的。为什么呢?因为如果插入一个黑色结点,那么性质(5)瞬间被破坏。接下来,就会遇到以下几种情况:

1.原来的树是一颗空树,则直接把新插入的结点的颜色改为黑色

2.新插入结点的父结点是黑色,无需任何操作。(因为新插入一个红色结点在这种情况下不破坏红黑树的任何性质)

3.新插入结点的父结点是红色,破坏了性质(4)

    第1,2种情况都是很乐观的,主要问题就在于第3种情况,解决这种情况需要考虑到新插入结点的叔叔结点。首先设新插入的结点为x, 其父亲为px, 叔叔为u。假定px是A的左孩子来分析问题。(px是A的右孩子的情况是类似的,只是某些操作是反过来而已(旋转))。

Case 1:如果叔叔u为红色

 

直接把新插入结点x的父亲px和叔叔u染成黑色,并将x的祖父A染成红色。其实这种情况可以这样理解,红黑树中性质(5)的保持,A是做了贡献的,它贡献了一个黑色。这个操作就相当于把它的黑色往下“推”了。至于为什么A一定是黑色?因为u是红色,根据性质(4),A不可能是红色。接下来,由于A变成了红色,那么如果A的父亲也是红色呢?所以插入是一个循环的过程,接下来就要查看A的情况了,这时它就相当于最初的x了。

Case 2:如果叔叔u是黑色的,并且x是px的左孩子

由于u是黑色的,它是对性质(5)有贡献的,按照原来“下推”的操作已经没办法完成了。因为这样的话(root->...->A->u->...)这条路径就少了一个黑色。所以,这种情况下的解决办法是把新插入结点x的父亲px染成黑色,把它的祖父A染成红色,然后对A进行一次右旋。对于这种情况,其实就相当于把px的红色转到右子树去了,又因为u是黑色,所以把红色转过去不会影响性质(4)。

Case 3:如果叔叔u是黑色的,并且x是px的右孩子

这种情况首先对新插入结点x的父亲px进行一次左旋。然后得到的结果正好跟Case 2一样了。

    红黑树的插入操作就几种,对于px是其父亲A的右孩子的情况,则如上述所言,是镜像的。

代码如下:

 1 template <typename T> void RedBlackTree <T>::insert(const T &data)
 2 {
 3     RBTreeNode <T> *pNewNode = new RBTreeNode <T>(data);
 4     RBTreeNode <T> *pNode = pRoot, *pPreNode = NULL;
 5     while (pNode != NULL)
 6     {
 7         pPreNode = pNode;
 8         if (pNode->m_nValue <= data)
 9             pNode = pNode->m_pRight;
10         else
11             pNode = pNode->m_pLeft;
12     }
13     if (pPreNode == NULL)
14     {
15         pRoot = pNewNode;
16     }
17     else
18     {
19         if (pPreNode->m_nValue <= data)
20             pPreNode->m_pRight = pNewNode;
21         else
22             pPreNode->m_pLeft = pNewNode;
23         pNewNode->m_pParent = pPreNode;
24     }
25     insert_fixed(pNewNode);
26     total_nodes++;
27 }
28 
29 template <typename T> void RedBlackTree <T>::insert_fixed(RBTreeNode <T> *&root)
30 {
31     if (root == NULL)
32         return;
33     RBTreeNode <T> *pParent = NULL;
34     while (root->color == red) //如果当前结点是红色的,可能其父亲也是红色的
35     {
36         pParent = root->m_pParent;
37         if (pParent == NULL || pParent->color != red || pParent->m_pParent == NULL) //父亲不是红色,结束
38             break;
39         RBTreeNode <T> *pGrandparent = pParent->m_pParent;
40         RBTreeNode <T> *pUncle = NULL;
41         if (pGrandparent->m_pLeft == pParent)
42             pUncle = pGrandparent->m_pRight;
43         else if (pGrandparent->m_pRight == pParent)
44             pUncle = pGrandparent->m_pLeft;
45         if (pUncle != NULL && pUncle->color == red) //叔叔结点是红色的
46         {
47             pParent->color = black;
48             pUncle->color = black;
49             pGrandparent->color = red;
50         }
51         else //叔叔结点为空或者为黑色
52         {
53             if (pParent == pGrandparent->m_pLeft)
54             {
55                 if (root == pParent->m_pRight)
56                     rotate_left(pParent);
57                 pParent->color = black;
58                 pGrandparent->color = red;
59                 rotate_right(pGrandparent);
60             }
61             else if (pParent == pGrandparent->m_pRight)
62             {
63                 if (root == pParent->m_pLeft)
64                     rotate_right(pParent);
65                 pParent->color = black;
66                 pGrandparent->color = red;
67                 rotate_left(pGrandparent);
68             }
69         }
70         root = pGrandparent; //往树上爬,看是否还有违反性质的结点
71     }
72     pRoot->color = black;
73 }

<h1 style="margin: 0px; padding: 0px; font-size: 28px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; color: rgb(51, 102, 255); font-size: 15px;">红黑树的删除操作</span></h1><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">    这部分就麻烦多了。但是作为真男人,有困难要上,没困难,制造困难也要上......</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">    首先,红黑树是二叉树,它的删除跟普通二叉查找树如出一辙,问题还是在于维护它的结构。最理想的情况是,被删除的结点是一个红色结点,那么万事大吉,直接删掉就可以了,其他什么事都不用干。因为它不会影响上述(1)~(5)所有性质。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">    如果删除的是黑色结点,那么就有如下几种情况了(这里也以被删除的结点都是其父亲的左孩子为例子,相反情况则镜像):</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">1.删除一个结点后,必然是它的一个孩子(可能为NULL)替补上来,如果这个孩子是红色的话,那就好办了,直接把这个替补结点染成黑色即可。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">首先看看删除的结点只有一个孩子的情况:</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><img src="http://images.cnitblog.com/i/471144/201405/230048089966632.jpg" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">这里d不管是被删除的结点a的左孩子还是右孩子,d都是替换a的,d最后成为了rt的左孩子。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">如果被删除的结点有两个孩子的话:</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><img src="http://images.cnitblog.com/i/471144/201405/230059143714323.jpg" alt="" style="margin: 0px; padding: 0px; border: 0px;" /></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">这里要删除的结点是a,跟普通二叉查找树的删除一样,找到其后继f,f如果是后继,那么它必然无左子树。然后,把h替换到f这个位置,而把f替换到a这个位置。因为h是红色,直接染成黑色就可以了。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">2.如果替补上来的结点也是黑色,这就是最麻烦的地方了。因为被删除的结点是黑色(假定为a结点),这必然导致它的某个祖先违反了性质(5),因为从该祖先到a的所有子树上的路径的黑色结点数都少了1,而替补上来的又恰好是黑的,没办法填补这个失去的一个黑色了。为了保持性质(5)不被破坏,《算法导论》里说把替补上来的结点当成有两重黑色,这样便填补了那个失去的一个黑色,但问题在于,这样的话替补结点违反了性质(1)!每个结点只能是黑色或红色,而这个替补结点却是双重黑色。于是,问题就在于如何把替补结点的双重黑色去掉一重,从而保持性质(1)不被破坏。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">这里的解决方法按四步走,需要注意的是,删除后重新维护红黑树结构的四个步骤并不是一步到位的!而是通过重复走这四个步骤中的某几个,最终把性质(1)保持下来。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><span style="margin: 0px; padding: 0px;">Step 1:替补结点的兄弟是红色的</span></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><img src="http://images.cnitblog.com/i/471144/201405/230122433716732.jpg" alt="" width="697" height="175" style="margin: 0px; padding: 0px; border: 0px;" /></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">这里要删除的结点是a,其后继为f,而替补f的h是黑色的。通过替换操作后,得到第二个图。h是双重黑色的,而它的兄弟g是红色的。这时的操作是,把g染成黑色,把e染成红色,得到第三个图。最后,将e进行一次左旋得到第四个图。需要注意的是,这时并不是说性质(1)就得到保持了,此时h的双重黑色还在,接下来的操作就得看结点 i 颜色了。如果结点 i 是红色,那么进行的还是Step 1,如果 i 是黑色,则进行其他步骤。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><span style="margin: 0px; padding: 0px;">Step 2:替补结点的兄弟是黑色的,并且其兄弟结点的两个孩子都是黑色的</span></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><img src="http://images.cnitblog.com/i/471144/201405/230133035744457.jpg" alt="" width="678" height="173" style="margin: 0px; padding: 0px; border: 0px;" /></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">同样,经过替换后得到第二个图。此时h的兄弟g为黑色,并且g有两个黑色的孩子,这时把g染成红色,并把h那多余的一重黑色上升到e上面,如果e为红色,直接把e染成黑色就大功告成了。上述图示里e就恰好是红色。那如果e是黑色呢?此时e变成双重黑色了,接下来的操作,就看e的兄弟是什么状况了,然后再根据状况去选择步骤。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><span style="margin: 0px; padding: 0px;">Step 3:替补结点的兄弟是黑色的,且其左孩子结点是红色的,右孩子的结点是黑色的。</span></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><img src="http://images.cnitblog.com/i/471144/201405/230149402936587.jpg" alt="" width="658" height="160" style="margin: 0px; padding: 0px; border: 0px;" /></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">照旧,先替换得到第二个图,这是h是双重黑色的,其兄弟g为黑色,且有一个红色左孩子 i 和黑色左孩子 j,这时把 i 染成黑色,并把兄弟g染成红色得到第三个图。对兄弟g进行右旋得到第四个图。此时,h的兄弟是 i 了,把 i 染成其父亲e的颜色,并把其父亲e和右孩子g染成黑色得到第五个图。最后对e进行一次左旋,得到第六个图。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><span style="margin: 0px; padding: 0px;">Step 4:替补结点的兄弟是黑色的,且其右孩子结点是红色的。</span></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;"><img src="http://images.cnitblog.com/i/471144/201405/230157557468290.jpg" alt="" width="638" height="182" style="margin: 0px; padding: 0px; border: 0px;" /></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">替换得到的第二个图恰好跟 Step 3里的第四个图是一样的。其实这不是恰好,而是Step 3目的就是为了转换成Step 4的。到了Step 4,所以转换都完成了,因为h多余的那层黑色被转换到了其兄弟那颗树中去了(原本红色的 j 变成了黑色)。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">    至此,删除的所有操作都结束了。需要注意的是,以上所有的“左”,“右”都是以“被删除结点是其父亲的左孩子”为例子而言的,如果不是,则恰好相反。</span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; line-height: 18px; color: rgb(68, 68, 68); font-family: tahoma, arial, sans-serif; background-color: rgb(255, 255, 255);"><span style="margin: 0px; padding: 0px; font-size: 15px;">代码如下:</span></p><pre name="code" class="cpp">  1 template <typename T> void RedBlackTree <T>::remove(const T &data)
  2 {
  3     if (pRoot == NULL)
  4         return;
  5     RBTreeNode <T> *pNode = pRoot;
  6     while (pNode != NULL)
  7     {
  8         if (pNode->m_nValue == data)
  9             break;
 10         else if (pNode->m_nValue < data)
 11             pNode = pNode->m_pRight;
 12         else
 13             pNode = pNode->m_pLeft;
 14     }
 15     if (pNode == NULL) //树中没有该结点
 16         return;
 17     Color delete_color; //被删除结点的颜色
 18     Direction direction; //替补结点是其父亲的哪个子树,左或右
 19     RBTreeNode <T> *pParent = NULL;
 20     if (pNode->m_pLeft != NULL && pNode->m_pRight != NULL) //删除的结点有两个孩子,需要找到后继
 21     {
 22         RBTreeNode <T> *pSuccessor = pNode->m_pRight;
 23         while (pSuccessor->m_pLeft != NULL)
 24             pSuccessor = pSuccessor->m_pLeft;
 25         pParent = pSuccessor->m_pParent;
 26         if (pParent->m_pLeft == pSuccessor)
 27         {
 28             pParent->m_pLeft = pSuccessor->m_pRight;
 29             direction = _left;
 30         }
 31         else if (pParent->m_pRight == pSuccessor)
 32         {
 33             pParent->m_pRight = pSuccessor->m_pRight;
 34             direction = _right;
 35         }
 36         if (pSuccessor->m_pRight != NULL)
 37             pSuccessor->m_pRight->m_pParent = pParent;
 38         pNode->m_nValue = pSuccessor->m_nValue;
 39         delete_color = pSuccessor->color;
 40         delete pSuccessor;
 41         pSuccessor = NULL;
 42     }
 43     else if (pNode->m_pLeft != NULL) //删除的结点只有左孩子
 44     {
 45         RBTreeNode <T> *pChild = pNode->m_pLeft;
 46         pParent = pNode->m_pParent;
 47         pNode->m_nValue = pChild->m_nValue;
 48         pNode->m_pLeft = NULL;
 49         delete_color = pChild->color;
 50         if (pParent != NULL)
 51         {
 52             if (pParent->m_pLeft == pNode)
 53                 direction = _left;
 54             else if (pParent->m_pRight == pNode)
 55                 direction = _right;
 56         }
 57         delete pChild;
 58         pChild = NULL;
 59     }
 60     else if (pNode->m_pRight != NULL) //删除的结点只有右孩子
 61     {
 62         RBTreeNode <T> *pChild = pNode->m_pRight;
 63         pParent = pNode->m_pParent;
 64         pNode->m_nValue = pChild->m_nValue;
 65         pNode->m_pRight = NULL;
 66         delete_color = pChild->color;
 67         if (pParent != NULL)
 68         {
 69             if (pParent->m_pLeft == pNode)
 70                 direction = _left;
 71             else if (pParent->m_pRight == pNode)
 72                 direction = _right;
 73         }
 74         delete pChild;
 75         pChild = NULL;
 76     }
 77     else
 78     {
 79         pParent = pNode->m_pParent;
 80         delete_color = pNode->color;
 81         if (pParent != NULL)
 82         {
 83             if (pParent->m_pLeft == pNode)
 84                 direction = _left;
 85             else if (pParent->m_pRight == pNode)
 86                 direction = _right;
 87         }
 88         if (pParent->m_pLeft == pNode)
 89             pParent->m_pLeft = NULL;
 90         else if (pParent->m_pRight == pNode)
 91             pParent->m_pRight = NULL;
 92         delete pNode;
 93         pNode = NULL;
 94     }
 95     if (pParent == NULL)
 96         pRoot->color = black;
 97     else if (delete_color == black)
 98         remove_fixed(pParent, direction);
 99     total_nodes--;
100 }
101 
102 template <typename T> void RedBlackTree <T>::remove_fixed(RBTreeNode <T> *&root, Direction direction)
103 {
104     if (root == NULL)
105         return;
106     RBTreeNode <T> *pNode = direction == _left ? root->m_pLeft : root->m_pRight;
107     while (pNode != pRoot)
108     {
109         if (pNode != NULL && pNode->color == red)
110             break;
111         RBTreeNode <T> *pBrother = direction == _left ? root->m_pRight : root->m_pLeft;
112         if (pBrother != NULL && pBrother->color == red)
113         {
114             pBrother->color = black;
115             root->color = red;
116             if (direction == _left)
117             {
118                 rotate_left(root);
119                 root = root->m_pLeft;
120                 if (root != NULL)
121                 {
122                     pNode = root->m_pLeft;
123                     pBrother = root->m_pRight;
124                 }
125             }
126             else if (direction == _right)
127             {
128                 rotate_right(root);
129                 root = root->m_pRight;
130                 if (root != NULL)
131                 {
132                     pNode = root->m_pRight;
133                     pBrother = root->m_pLeft;
134                 }
135             }
136         }
137         if (pBrother == NULL)
138         {
139             pNode = root;
140             if (root != NULL)
141             {
142                 root = root->m_pParent;
143                 if (root != NULL)
144                 {
145                     if (root->m_pLeft == pNode)
146                         direction = _left;
147                     else if (root->m_pRight == pNode)
148                         direction = _right;
149                 }
150             }
151         }
152         else if ((pBrother->m_pLeft == NULL || pBrother->m_pLeft->color == black) &&
153             (pBrother->m_pRight == NULL || pBrother->m_pRight->color == black))
154         {
155 
156             pBrother->color = red;
157             pNode = root;
158             if (root != NULL)
159             {
160                 root = root->m_pParent;
161                 if (root != NULL)
162                 {
163                     if (root->m_pLeft == pNode)
164                         direction = _left;
165                     else if (root->m_pRight == pNode)
166                         direction = _right;
167                 }
168             }
169         }
170 
171         else if (pBrother != NULL)
172         {
173             if (pBrother->m_pRight == NULL || pBrother->m_pRight->color == black)
174             {
175                 if (pBrother->m_pLeft != NULL)
176                     pBrother->m_pLeft->color = black;
177                 pBrother->color = red;
178                 if (direction == _left)
179                     rotate_right(pBrother);
180                 else if (direction == _right)
181                     rotate_left(pBrother);
182             }
183             pBrother->color = root->color;
184             root->color = black;
185             if (direction == _left)
186             {
187                 rotate_left(root);
188                 if (pBrother->m_pRight != NULL)
189                     pBrother->m_pRight->color = black;
190             }
191             else if (direction == _right)
192             {
193                 rotate_right(root);
194                 if (pBrother->m_pLeft != NULL)
195                     pBrother->m_pLeft->color = black;
196             }
197             pNode = pRoot;
198         }
199     }
200     pNode->color = black;
201 }


 
    完整的代码如下,由于没有采用《算法导论》里的“哨兵”方法,代码中多了很多判断语句,显得冗长。改日再改成“哨兵”的方法。 
  

  1 #include <iostream>
  2 #include <stdexcept>
  3 
  4 using namespace std;
  5 
  6 //枚举类型,分别是结点的颜色
  7 enum Color
  8 {
  9     red, black
 10 };
 11 //红黑树结点定义
 12 template <typename T> 
 13 class RBTreeNode
 14 {
 15 public:
 16     RBTreeNode();
 17     RBTreeNode(const T &);
 18     RBTreeNode(const RBTreeNode &);
 19 public:
 20     T m_nValue;
 21     Color color;
 22     RBTreeNode *m_pParent;
 23     RBTreeNode *m_pLeft;
 24     RBTreeNode *m_pRight;
 25 };
 26 
 27 template <typename T> RBTreeNode <T>::RBTreeNode()
 28 {
 29     m_pParent = NULL;
 30     m_pLeft = NULL;
 31     m_pRight = NULL;
 32 }
 33 template <typename T> RBTreeNode <T>::RBTreeNode(const T &rhs)
 34 {
 35     m_nValue = rhs;
 36     color = red;
 37     m_pParent = NULL;
 38     m_pLeft = NULL;
 39     m_pRight = NULL;
 40 }
 41 template <typename T> RBTreeNode <T>::RBTreeNode(const RBTreeNode <T> &rhs)
 42 {
 43     m_nValue = rhs.m_nValue;
 44     color = rhs.color;
 45     m_pParent = rhs.m_pParent;
 46     m_pLeft = rhs.m_pLeft;
 47     m_pRight = rhs.m_pRight;
 48 }
 49 
 50 //-----------------------------分割线-----------------------------
 51 
 52 enum Direction
 53 {
 54     _left, _right
 55 };
 56 //红黑树的操作定义
 57 template <typename T>
 58 class RedBlackTree
 59 {
 60 public:
 61     RedBlackTree();
 62     ~RedBlackTree();
 63     bool empty();
 64     size_t size();
 65     void insert(const T &);
 66     void remove(const T &);
 67     bool search(const T &);
 68     T maximun();
 69     T minimun();
 70 private:
 71     void insert_fixed(RBTreeNode <T> *&);
 72     void remove_fixed(RBTreeNode <T> *&, Direction);
 73     void rotate_left(RBTreeNode <T> *&);
 74     void rotate_right(RBTreeNode <T> *&);
 75     void delete_all(RBTreeNode <T> *&);
 76 private:
 77     //把复制构造函数和赋值操作符声明为private且不定义,目的是拒绝编译器生成的版本。意思就是树不能被复制。
 78     RedBlackTree(const RedBlackTree <T> &);
 79     RedBlackTree & operator= (const RedBlackTree <T> &);
 80 private:
 81     RBTreeNode <T> *pRoot;
 82     size_t total_nodes;
 83 };
 84 
 85 template <typename T> RedBlackTree <T>::RedBlackTree()
 86 {
 87     pRoot = NULL;
 88     total_nodes = 0;
 89 }
 90 template <typename T> RedBlackTree <T>::~RedBlackTree()
 91 {
 92     delete_all(pRoot);
 93     total_nodes = 0;
 94 }
 95 template <typename T> bool RedBlackTree <T>::empty()
 96 {
 97     return total_nodes == 0 ? true : false;
 98 }
 99 template <typename T> size_t RedBlackTree <T>::size()
100 {
101     return total_nodes;
102 }
103 template <typename T> void RedBlackTree <T>::insert(const T &data)
104 {
105     RBTreeNode <T> *pNewNode = new RBTreeNode <T>(data);
106     RBTreeNode <T> *pNode = pRoot, *pPreNode = NULL;
107     while (pNode != NULL)
108     {
109         pPreNode = pNode;
110         if (pNode->m_nValue <= data)
111             pNode = pNode->m_pRight;
112         else
113             pNode = pNode->m_pLeft;
114     }
115     if (pPreNode == NULL)
116     {
117         pRoot = pNewNode;
118     }
119     else
120     {
121         if (pPreNode->m_nValue <= data)
122             pPreNode->m_pRight = pNewNode;
123         else
124             pPreNode->m_pLeft = pNewNode;
125         pNewNode->m_pParent = pPreNode;
126     }
127     insert_fixed(pNewNode);
128     total_nodes++;
129 }
130 template <typename T> void RedBlackTree <T>::remove(const T &data)
131 {
132     if (pRoot == NULL)
133         return;
134     RBTreeNode <T> *pNode = pRoot;
135     while (pNode != NULL)
136     {
137         if (pNode->m_nValue == data)
138             break;
139         else if (pNode->m_nValue < data)
140             pNode = pNode->m_pRight;
141         else
142             pNode = pNode->m_pLeft;
143     }
144     if (pNode == NULL) //树中没有该结点
145         return;
146     Color delete_color; //被删除结点的颜色
147     Direction direction; //替补结点是其父亲的哪个子树,左或右
148     RBTreeNode <T> *pParent = NULL;
149     if (pNode->m_pLeft != NULL && pNode->m_pRight != NULL) //删除的结点有两个孩子,需要找到后继
150     {
151         RBTreeNode <T> *pSuccessor = pNode->m_pRight;
152         while (pSuccessor->m_pLeft != NULL)
153             pSuccessor = pSuccessor->m_pLeft;
154         pParent = pSuccessor->m_pParent;
155         if (pParent->m_pLeft == pSuccessor)
156         {
157             pParent->m_pLeft = pSuccessor->m_pRight;
158             direction = _left;
159         }
160         else if (pParent->m_pRight == pSuccessor)
161         {
162             pParent->m_pRight = pSuccessor->m_pRight;
163             direction = _right;
164         }
165         if (pSuccessor->m_pRight != NULL)
166             pSuccessor->m_pRight->m_pParent = pParent;
167         pNode->m_nValue = pSuccessor->m_nValue;
168         delete_color = pSuccessor->color;
169         delete pSuccessor;
170         pSuccessor = NULL;
171     }
172     else if (pNode->m_pLeft != NULL) //删除的结点只有左孩子
173     {
174         RBTreeNode <T> *pChild = pNode->m_pLeft;
175         pParent = pNode->m_pParent;
176         pNode->m_nValue = pChild->m_nValue;
177         pNode->m_pLeft = NULL;
178         delete_color = pChild->color;
179         if (pParent != NULL)
180         {
181             if (pParent->m_pLeft == pNode)
182                 direction = _left;
183             else if (pParent->m_pRight == pNode)
184                 direction = _right;
185         }
186         delete pChild;
187         pChild = NULL;
188     }
189     else if (pNode->m_pRight != NULL) //删除的结点只有右孩子
190     {
191         RBTreeNode <T> *pChild = pNode->m_pRight;
192         pParent = pNode->m_pParent;
193         pNode->m_nValue = pChild->m_nValue;
194         pNode->m_pRight = NULL;
195         delete_color = pChild->color;
196         if (pParent != NULL)
197         {
198             if (pParent->m_pLeft == pNode)
199                 direction = _left;
200             else if (pParent->m_pRight == pNode)
201                 direction = _right;
202         }
203         delete pChild;
204         pChild = NULL;
205     }
206     else
207     {
208         pParent = pNode->m_pParent;
209         delete_color = pNode->color;
210         if (pParent != NULL)
211         {
212             if (pParent->m_pLeft == pNode)
213                 direction = _left;
214             else if (pParent->m_pRight == pNode)
215                 direction = _right;
216         }
217         if (pParent->m_pLeft == pNode)
218             pParent->m_pLeft = NULL;
219         else if (pParent->m_pRight == pNode)
220             pParent->m_pRight = NULL;
221         delete pNode;
222         pNode = NULL;
223     }
224     if (pParent == NULL)
225         pRoot->color = black;
226     else if (delete_color == black)
227         remove_fixed(pParent, direction);
228     total_nodes--;
229 }
230 template <typename T> bool RedBlackTree <T>::search(const T &data)
231 {
232     if (pRoot == NULL)
233         return false;
234     RBTreeNode <T> *pNode = pRoot;
235     while (pNode != NULL)
236     {
237         if (pNode->m_nValue == data)
238             return true;
239         else if (pNode->m_nValue <= data)
240             pNode = pNode->m_pRight;
241         else if (pNode->m_nValue > data)
242             pNode = pNode->m_pLeft;
243     }
244     return false;
245 }
246 template <typename T> T RedBlackTree <T>::maximun()
247 {
248     if (pRoot == NULL)
249         throw range_error("The Red-Black Tree is empty");
250     RBTreeNode <T> *pNode = pRoot;
251     while (pNode->m_pRight != NULL)
252         pNode = pNode->m_pRight;
253     return pNode->m_nValue;
254 }
255 template <typename T> T RedBlackTree <T>::minimun()
256 {
257     if (pRoot == NULL)
258         throw range_error("The Red-Black Tree is empty");
259     RBTreeNode <T> *pNode = pRoot;
260     while (pNode->m_pLeft != NULL)
261         pNode = pNode->m_pLeft;
262     return pNode->m_nValue;
263 }
264 template <typename T> void RedBlackTree <T>::insert_fixed(RBTreeNode <T> *&root)
265 {
266     if (root == NULL)
267         return;
268     RBTreeNode <T> *pParent = NULL;
269     while (root->color == red) //如果当前结点是红色的,可能其父亲也是红色的
270     {
271         pParent = root->m_pParent;
272         if (pParent == NULL || pParent->color != red || pParent->m_pParent == NULL) //父亲不是红色,结束
273             break;
274         RBTreeNode <T> *pGrandparent = pParent->m_pParent;
275         RBTreeNode <T> *pUncle = NULL;
276         if (pGrandparent->m_pLeft == pParent)
277             pUncle = pGrandparent->m_pRight;
278         else if (pGrandparent->m_pRight == pParent)
279             pUncle = pGrandparent->m_pLeft;
280         if (pUncle != NULL && pUncle->color == red) //叔叔结点是红色的
281         {
282             pParent->color = black;
283             pUncle->color = black;
284             pGrandparent->color = red;
285         }
286         else //叔叔结点为空或者为黑色
287         {
288             if (pParent == pGrandparent->m_pLeft)
289             {
290                 if (root == pParent->m_pRight)
291                     rotate_left(pParent);
292                 pParent->color = black;
293                 pGrandparent->color = red;
294                 rotate_right(pGrandparent);
295             }
296             else if (pParent == pGrandparent->m_pRight)
297             {
298                 if (root == pParent->m_pLeft)
299                     rotate_right(pParent);
300                 pParent->color = black;
301                 pGrandparent->color = red;
302                 rotate_left(pGrandparent);
303             }
304         }
305         root = pGrandparent; //往树上爬,看是否还有违反性质的结点
306     }
307     pRoot->color = black;
308 }
309 template <typename T> void RedBlackTree <T>::remove_fixed(RBTreeNode <T> *&root, Direction direction)
310 {
311     if (root == NULL)
312         return;
313     RBTreeNode <T> *pNode = direction == _left ? root->m_pLeft : root->m_pRight;
314     while (pNode != pRoot)
315     {
316         if (pNode != NULL && pNode->color == red)
317             break;
318         RBTreeNode <T> *pBrother = direction == _left ? root->m_pRight : root->m_pLeft;
319         if (pBrother != NULL && pBrother->color == red)
320         {
321             pBrother->color = black;
322             root->color = red;
323             if (direction == _left)
324             {
325                 rotate_left(root);
326                 root = root->m_pLeft;
327                 if (root != NULL)
328                 {
329                     pNode = root->m_pLeft;
330                     pBrother = root->m_pRight;
331                 }
332             }
333             else if (direction == _right)
334             {
335                 rotate_right(root);
336                 root = root->m_pRight;
337                 if (root != NULL)
338                 {
339                     pNode = root->m_pRight;
340                     pBrother = root->m_pLeft;
341                 }
342             }
343         }
344         if (pBrother == NULL)
345         {
346             pNode = root;
347             if (root != NULL)
348             {
349                 root = root->m_pParent;
350                 if (root != NULL)
351                 {
352                     if (root->m_pLeft == pNode)
353                         direction = _left;
354                     else if (root->m_pRight == pNode)
355                         direction = _right;
356                 }
357             }
358         }
359         else if ((pBrother->m_pLeft == NULL || pBrother->m_pLeft->color == black) &&
360             (pBrother->m_pRight == NULL || pBrother->m_pRight->color == black))
361         {
362 
363             pBrother->color = red;
364             pNode = root;
365             if (root != NULL)
366             {
367                 root = root->m_pParent;
368                 if (root != NULL)
369                 {
370                     if (root->m_pLeft == pNode)
371                         direction = _left;
372                     else if (root->m_pRight == pNode)
373                         direction = _right;
374                 }
375             }
376         }
377 
378         else if (pBrother != NULL)
379         {
380             if (pBrother->m_pRight == NULL || pBrother->m_pRight->color == black)
381             {
382                 if (pBrother->m_pLeft != NULL)
383                     pBrother->m_pLeft->color = black;
384                 pBrother->color = red;
385                 if (direction == _left)
386                     rotate_right(pBrother);
387                 else if (direction == _right)
388                     rotate_left(pBrother);
389             }
390             pBrother->color = root->color;
391             root->color = black;
392             if (direction == _left)
393             {
394                 rotate_left(root);
395                 if (pBrother->m_pRight != NULL)
396                     pBrother->m_pRight->color = black;
397             }
398             else if (direction == _right)
399             {
400                 rotate_right(root);
401                 if (pBrother->m_pLeft != NULL)
402                     pBrother->m_pLeft->color = black;
403             }
404             pNode = pRoot;
405         }
406     }
407     pNode->color = black;
408 }
409 template <typename T> void RedBlackTree <T>::rotate_left(RBTreeNode <T> *&root)
410 {
411     if (root == NULL || root->m_pRight == NULL)
412         return;
413     RBTreeNode <T> *pNode = root->m_pRight;
414     root->m_pRight = pNode->m_pLeft;
415     if (pNode->m_pLeft != NULL)
416         pNode->m_pLeft->m_pParent = root;
417     if (root->m_pParent == NULL)
418         pRoot = pNode;
419     else
420     {
421         if (root == root->m_pParent->m_pLeft)
422             root->m_pParent->m_pLeft = pNode;
423         else if (root == root->m_pParent->m_pRight)
424             root->m_pParent->m_pRight = pNode;
425     }
426     pNode->m_pParent = root->m_pParent;
427     pNode->m_pLeft = root;
428     root->m_pParent = pNode;
429     root = pNode;
430 }
431 template <typename T> void RedBlackTree <T>::rotate_right(RBTreeNode <T> *&root)
432 {
433     if (root == NULL || root->m_pLeft == NULL)
434         return;
435     RBTreeNode <T> *pNode = root->m_pLeft;
436     root->m_pLeft = pNode->m_pRight;
437     if (pNode->m_pRight != NULL)
438         pNode->m_pRight->m_pParent = root;
439     if (root->m_pParent == NULL)
440         pRoot = pNode;
441     else
442     {
443         if (root == root->m_pParent->m_pLeft)
444             root->m_pParent->m_pLeft = pNode;
445         else if (root == root->m_pParent->m_pRight)
446             root->m_pParent->m_pRight = pNode;
447     }
448     pNode->m_pParent = root->m_pParent;
449     pNode->m_pRight = root;
450     root->m_pParent = pNode;
451     root = pNode;
452 }
453 template <typename T> void RedBlackTree <T>::delete_all(RBTreeNode <T> *&root)
454 {
455     if (root == NULL)
456         return;
457     delete_all(root->m_pLeft);
458     delete_all(root->m_pRight);
459     delete root;
460     root = NULL;
461 }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值