红黑树

作为一种数据结构,红黑树可谓不算朴素,因为各种宣传让它过于神秘,网上搜罗了一大堆的关于红黑树的文章,不外乎千篇一律,介绍概念,分析性能,贴上代码,然后给上罪恶的一句话,它最坏情况怎么怎么地...
       
       我们想,一棵二叉树怎么就是最坏情况,那就是它退化为一个链表,这样查找就成了遍历。问题是,平衡二叉树怎么会退回链表!它是怎么保持平衡的?能不能简单 地阐述?当然可以!一般的讲述红黑树的资料都是直接给出黑节点相同,红节点不连续等来作为一个足够硬但是又不是太硬的约束来保证树的平衡,但事实上,它还 有更加简单的理解方式。
 

1.查找-在高度不在宽度

对于查找而言,如果一棵二叉树的高度是N,那么最多可以在N步内完成查找,这个不用解释,解释这个有点喧宾夺主了。这就是说,树的高度要尽可能矮。考虑到查找的平均情况,叶子节点到根节点的距离不能差别太大。
 

2.二叉树的不平衡根源

一棵树在查找看来变得不平衡是因为子树的高度相差很大。
       二叉树为什么会这么容易变得不平衡,很简单,因为它只有二叉,左右均有50%的概率,那么插入N个节点全部都是左节点或者右节点的概率就是50%的N次方,如果是8叉树,那么这个概率就是12.5%的N次方,哪个概率大,自己算。
 

3.多叉树-宽度换高度

在第1节以及第2节,我们已经知道,树的宽度越大,高度越小,这样查询起来越快,Cisco路由器里不是有256叉乃至1024叉树吗?但是这样真的很好吗?对于稀疏节点,这样会严重消耗内存。
       如果我们考虑CPU的MMU系统,就会知道,二级页表和三级页表的区别就在于对付稀疏地址空间的效果不同。
 

4.权衡-2,3树

我 们发现,道生一,一生二,二叉树是一个完美的开始,但是我们发现它特别容易倾斜,倾斜的时候别触摸。我们也不能一下子就上256叉树,即使那样在海量节点 情况下也抗不住,因此这种盲目宽度换高度的方案没有可扩展性。我们需要找出一种动态的机制,让一棵树动态调整保持平衡。
       为了更加容易找出这个机制,让它更加容易现形,暂时不断增加树的宽度,如果增加到3叉树还找不到方案,就增加到4叉树...我们说的N叉树并不是说一个节点一定有N个子节点,而是说它最多有N个子节点。
       迄今为止,以前都是我自己形而上的观点,几年前我的想法就到此为止,原因在于那段时间特别郁闷,就想找出些技术上的形而上思想,可是突然自己变好了,就没有继续下去。幸运的是,我现在发现确实有这么一个方案,而红黑树就是从3叉树回退过去的。
       让我高兴的是,我的思路并没有跑偏。

5.2-3树的平衡变换

如果是二叉树,那么你插入一个节点,你只有最多1次机会保持子树的高度不变,如果是一个三叉树,那么就有2次机会。现在开始,我们为二叉树添了一叉,变成了三叉树。

       二叉树的时候,一个节点有两个分支,三叉树的时候,有三个分支。一个点可以将区间分为两个部分区域,要想将一个区间分为三个部分区域,就需要两个点,因此三叉的情形下,节点存储的是两个点而不是一个,如下图所示:

wKioL1WOxwOAC-dLAAAr9C9bYYQ627.jpg
现在考虑插入一个新节点,这个2-3树怎么保持平衡。非常简单,我们知道,插入的位置一定是叶子,假设当前的树是平衡的,现在分两种情况:

1).插入的新叶子节点的父节点是一个二叉节点

这种情况最简单,二叉节点变三叉节点即可,如下图所示:

wKiom1WOxVOTymzUAACFywO_xR4614.jpg

2).插入的新叶子节点的父节点是一个三叉节点

这种情况比较复杂。树总是要长高的,保持平衡的方式就是同时长高,而这是不可能的,插入一个节点只能让该节点所在的子树长高。然而,如果能将这个信息上升到根部,在根部长高,就实现了“同时长高”!
       还是循着上面的那个思路,我们继续增加树叉的数量,我们把它增加到4!新节点的插入如下图所示:

wKiom1WOxWPghGMyAAGt_5c2nNg174.jpg

 

很遗憾,没有完成任务,但是最终我们提出了两个问题,只要解决了这两个问题,所有问题就解决了。

       解决这两个问题,无疑都要牵扯到节点P的父节点以及再往上的节点,有两种可能:
可能性1:P的父节点PP是一个二叉节点
这个太爽,我们直接把P以及它的子树全部提到PP节点即可,类似B插入的情景,如下图所示:
 

wKioL1WOxzPwE1kCAACrd-FZJpM560.jpg

 

问题2解决。

可能性2:P的父节点PP是一个三叉节点
这就有点不好办了,不过有最后一击!不管怎样先把P节点以及其子节点全部上提到PP,保持最底部的平衡性,这样就可以递归解决了,此时我们又一次遇到了往一个三叉节点里面插入子节点的问题了,为了不增加树高,唯一的方式就是膨胀成一个四叉节点-宽度换高度。如下图所示:
 

wKiom1WOxYWy5xH0AAHa0oqNNPI015.jpg

 

最后,我们发现,在递归的过程中,要么碰到了P..P是个二叉节点,此时按照问题2的解决方式将当前节点的值直接提到P...P中,其子树降低一个高度,抵消增加的高度,平衡保持,递归结束,要么递归到了根节点,此时只需要一个分裂操作即可完美结束!


 

6.演进到红黑树

很显然,通过上面的描述,我们似乎找到了一个使树保持平衡的方案,而且是相当完美的平衡!核心就是宽度和高度之间的博弈。我们总是可以用一个宽度抵消一层高度,整个过程就是一次或者多次的一加一减,最终的结果还是0!
       然而,这也不再是二叉树了,有的节点变成了三叉,并且保存了两个值,该两个值将区间分割成了三部分,是为三叉!因此在使用上就不如二叉树方便,比较操作复杂化了。事实上,将三叉节点处理成二叉节点,这棵树就成了红黑树!怎么处理呢?很简单!如下图所示:
 

wKioL1WOx1TxJkQKAABuVqDu2Ys804.jpg

 

看到了吧,红色节点就是从2-3树中分出来的,为了维持一棵二叉树而不是2-3树,必须将三叉节点变成二叉节点,这是一个宽度换高度得回退,即高度换宽度,当然代价就是不再完美平衡。

       按照以上的这个变换,你自己试试看,可以变出两个连续的红节点吗?NO!还在纠结红黑树的性质概念吗?看了它的演进,你会发现,很多红黑树的复杂概念和让人没有头绪的性能都是自然而然的。下面我们来看一下它的最坏情况是什么。
       还是以2-3树分析,如果在一棵2-3树中,最左边路径上的节点全部是三叉节点,而最右边路径上的节点都是二叉节点,那么把它变换成二叉红黑树之后,就会 发现最左边的路径上是红黑间隔的节点,而最右边的路径上全部是黑节点,它们的高度差接近2倍。出现这样的情况是令人悲哀的,但是也是极低概率的。
       红黑树的所有包括旋转等操作,都可以映射到2-3树中,而我们对2-3树以及高度和宽度之间的博弈已经足够理解了。请再次去理解红黑树吧,再看看它的性质和概念,together with左旋和右旋,是不是有一种新的体会呢?

 

      红黑树C语言实现:

 

  1. #include<iostream>
  2. #include<time.h>
  3. using namespace std;
  4. typedef int KEY;
  5. #define N 15
  6. enum NODECOLOR
  7. {
  8.     BLACK        = 0,
  9.     RED          = 1
  10. };
  11. typedef struct RBTree
  12. {
  13.     struct        RBTree *parent;
  14.     struct      RBTree *leftChild, *rightChild;
  15.     KEY            key;
  16.     NODECOLOR   color;
  17. }RBTree, *PRBTree;
  18. PRBTree ROOT;//根节点是ROOT
  19. void Mid_Visit(PRBTree &T);
  20. void LeftRotate(PRBTree &subroot)
  21. {
  22.     //cout<<" left rotate "<<endl;
  23.     PRBTree grandParent,parent,leftChild;//,rightChild;
  24.     grandParent=NULL;parent=NULL;leftChild=NULL;
  25.     if(subroot!=ROOT&&subroot!=NULL)parent=subroot->parent;//根节点是ROOT,
  26.     if(parent!=ROOT&&parent!=NULL)grandParent=parent->parent;
  27.     if(subroot->leftChild!=NULL)leftChild=subroot->leftChild;//如果subroot不为空,两个孩子都不为空,至多有虚拟节点,同样参与装换
  28.     //if(subroot->rightChild!=NULL)rightChild=subroot->rightChild;
  29.     if(grandParent!=NULL)
  30.     {
  31.         if(grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
  32.         else grandParent->rightChild=subroot;//grandparent不空,一定有左孩子,或右孩子并且至少有一个不是虚拟节点
  33.     /*if(grandParent->leftChild!=NULL&&grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
  34.     else if(grandParent->rightChild->key==parent->key)grandParent->rightChild=subroot;//有问题 if语句不成立条件*/
  35.     }
  36.     else//if  grandparent is null, then quadain parent is ROOT ,after left rotate, subroot becomes ROOT
  37.     {   // if quadain parent is root then change cannot happened for its color is balck.so this sentence will never be executed
  38.         //此判断不对,当进行一次有旋转后,在进行的左旋转就针对当前节点没有grandparent,而只有parent,而此时grandparent初始化为空了
  39.         ROOT=subroot;subroot->parent=NULL;subroot->color=BLACK;//cout<<" try judgement "<<endl;
  40.     }
  41.     //if(grandParent->leftChild!=NULL&&grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
  42.     //else if(grandParent->rightChild->key==parent->key)grandParent->rightChild=subroot;//有问题 if语句不成立条件
  43.     subroot->parent=grandParent;//2 grandparent可为空
  44.     parent->rightChild=leftChild;//1
  45.     if(leftChild!=NULL)leftChild->parent=parent;//2
  46.     parent->parent=subroot;//1
  47.     subroot->leftChild=parent;//2
  48.     //变颜色
  49.     //parent->color=RED;
  50.     //subroot->color=BLACK;
  51. }
  52. void RightRotate(PRBTree &subroot)
  53. {
  54.     //cout<<" right rotate "<<endl;
  55.     PRBTree grandParent,parent,rightChild;//leftChild;,
  56.     grandParent=NULL;parent=NULL;rightChild=NULL;
  57.     if(subroot!=ROOT&&subroot!=NULL)parent=subroot->parent;//根节点是ROOT,
  58.     if(parent!=ROOT&&parent!=NULL)grandParent=parent->parent;
  59.     if(subroot->rightChild!=NULL)rightChild=subroot->rightChild;
  60.     //if(subroot->rightChild!=NULL)rightChild=subroot->rightChild;
  61.     if(grandParent!=NULL)
  62.     {
  63.         if(grandParent->leftChild!=NULL&&grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
  64.     else if(grandParent->rightChild->key==parent->key)grandParent->rightChild=subroot;//有问题 if语句不成立条件
  65.     }
  66.     else//if  grandparent is null, then quadain parent is ROOT ,after right rotate, subroot baecomes ROOT
  67.     {
  68.         ROOT=subroot;subroot->parent=NULL;subroot->color=BLACK;
  69.     }
  70.     subroot->parent=grandParent;//2
  71.     parent->leftChild=rightChild;//1
  72.     if(rightChild!=NULL)rightChild->parent=parent;//2
  73.     parent->parent=subroot;//1
  74.     subroot->rightChild=parent;//2
  75.     //变颜色
  76.     //parent->color=RED;
  77.     //subroot->color=BLACK;
  78. }
  79. int check(PRBTree subroot)//subroot is new added node三个节点相连有四种情况.1.2.3.4,四个节点也有四种情况5,每种和三个节点有对应关系
  80. {
  81.     PRBTree parent,grandparent;
  82.     parent=NULL;grandparent=NULL;//指针都要初始化
  83.     if(subroot!=NULL&&subroot->parent!=NULL)parent=subroot->parent;
  84.     //cout<<" in test 12 "<<endl;
  85.      if(parent!=NULL&&parent->parent!=NULL)grandparent=parent->parent;
  86.     //cout<<" in test 13 "<<endl;
  87.     if(parent!=NULL&&parent->color==BLACK)return 0;//不用变换
  88.     else 
  89.     {
  90.         //cout<<" in test 14 "<<endl;
  91.         if(grandparent!=NULL)//grandparent不为空,则两个孩子也不为空
  92.         {
  93.          if(grandparent->leftChild->key!=0&&grandparent->leftChild->key==parent->key)
  94.          {
  95.              //cout<<" in test 15 "<<endl;
  96.             if(grandparent->rightChild->key!=0&&grandparent->rightChild->color==RED)//属于四个节点情况,四种情况一样处理,返回5
  97.             {
  98.                 //只有右节点不是虚拟节点时上面判断才有意义
  99.                     return 5; 
  100.                 //cout<<" in test 16 "<<endl;
  101.             }
  102.             else//属于三个节点情况
  103.             {
  104.                 //cout<<" in test 17 "<<endl;
  105.                 if(parent->leftChild==subroot)//parent肯定不是虚拟节点,
  106.                     return 1;
  107.                 else return 2;
  108.             }
  109.          }
  110.          else
  111.          {
  112.              //cout<<" in test 18 "<<endl;
  113.             if(grandparent->leftChild->key!=0&&grandparent->leftChild->color==RED)//属于四个节点情况,四种情况一样处理,返回5
  114.             {                
  115.                 return 5;
  116.             }
  117.             else//属于三个节点情况
  118.             {
  119.                 //cout<<" in test 19 "<<endl;
  120.                 if(parent->leftChild==subroot)
  121.                     return 4;
  122.                 else return 3;
  123.             }
  124.          }
  125.         }
  126.         else return 0;//当前只有两个节点
  127.     }
  128. }
  129. PRBTree find_insertPos(PRBTree &root,KEY key)//寻找插入位置,二分查找
  130. {
  131.     PRBTree p,q;
  132.     p=root;q=p;
  133.     while(q->key!=0)//判断是否虚拟节点
  134.     {
  135.         if(p->key>key)
  136.         {
  137.             q=p->leftChild;
  138.             if(q->key!=0)p=q;
  139.         }
  140.         else
  141.         {
  142.             q=p->rightChild;
  143.             if(q->key!=0)p=q;
  144.         }
  145.     }
  146.     return p;
  147. }
  148. void rotate(PRBTree &subroot)//针对新插入的节点
  149. {
  150.     //cout<<" in rotate "<<endl;
  151.     PRBTree parent,grandparent;
  152.     parent=NULL;grandparent=NULL;
  153.     if(subroot!=NULL&&subroot->parent!=NULL)parent=subroot->parent;
  154.     //cout<<" in test 10 "<<endl;
  155.      if(parent!=NULL&&parent->parent!=NULL)grandparent=parent->parent;
  156.     
  157.     //cout<<" in test 11 "<<endl;
  158.     switch(check(subroot))
  159.     {
  160.         //cout<<" in check "<<endl;
  161.     case 5://有四种情况
  162.         //cout<<" test check 5 "<<endl;
  163.         if(grandparent!=ROOT)grandparent->color=RED;
  164.         else grandparent->color=BLACK;
  165.         grandparent->leftChild->color=BLACK;
  166.         grandparent->rightChild->color=BLACK;
  167.         //check(grandparent);
  168.         //if(grandparent-parent!=NULL)
  169.         rotate(grandparent);//如果返回0,什么也不做
  170.     break;
  171.     case 1:
  172.         //cout<<" test check 1 "<<endl;
  173.         RightRotate(parent);
  174.         parent->color=BLACK;
  175.         //grandparent->color=RED;
  176.         if(grandparent!=ROOT)grandparent->color=RED;
  177.         else grandparent->color=BLACK;
  178.         //subroot->color=BLACK;
  179.     break;
  180.     case 2:
  181.         //cout<<" test check 2 "<<endl;
  182.     LeftRotate(subroot);
  183.     //cout<<"after leftrotate "<<endl;
  184.     //Mid_Visit(ROOT);//ROOT为根节点
  185.     RightRotate(subroot);
  186.     //cout<<"test whether rightrotate  "<<endl;
  187.     subroot->color=BLACK;
  188.     //if(grandparent!=ROOT)grandparent->color=RED;
  189.     if(grandparent!=ROOT)grandparent->color=RED;
  190.         else grandparent->color=BLACK;
  191.     break;
  192.     case 3:
  193.         //cout<<" test check 3 "<<endl;
  194.     LeftRotate(parent);
  195.     parent->color=BLACK;
  196.     //grandparent->color=RED;
  197.     if(grandparent!=ROOT)grandparent->color=RED;
  198.         else grandparent->color=BLACK;
  199.     break;
  200.     case 4:
  201.         //cout<<" test check 4 "<<endl;
  202.     RightRotate(subroot);
  203.     //LeftRotate(parent);//此时parent是subroot的右孩子
  204.     LeftRotate(subroot);
  205.     subroot->color=BLACK;
  206.     if(grandparent!=ROOT)grandparent->color=RED;
  207.     break;
  208.     case 0:
  209.         //cout<<" test check 0 "<<endl;
  210.         ;
  211.     }
  212. }
  213. void insert(PRBTree &root,KEY key)
  214. {
  215.     PRBTree p,q,news,vir1,vir2;
  216.         p=NULL;q=NULL;news=NULL;
  217.     if(root==NULL)
  218.     {
  219.         news=(PRBTree)new RBTree;//1,新建当前节点
  220.         news->leftChild=NULL;
  221.         news->rightChild=NULL;
  222.         news->parent=NULL;//根节点无父节点
  223.         news->color=BLACK;//根节点为黑色节点
  224.         news->key=key;
  225.         root=news;//root返回的也是根
  226.         ROOT=news;
  227.         // 新建2个虚拟节点vir1,vir2,颜色为黑,值为0;
  228.         vir1=(PRBTree)new RBTree;
  229.         vir1->leftChild=NULL;
  230.         vir1->rightChild=NULL;
  231.         vir1->parent=news;
  232.         vir1->color=BLACK;
  233.         vir1->key=0;
  234.         
  235.         vir2=(PRBTree)new RBTree;
  236.         vir2->leftChild=NULL;
  237.         vir2->rightChild=NULL;
  238.         vir2->parent=news;
  239.         vir2->color=BLACK;
  240.         vir2->key=0;
  241.         news->leftChild=vir1;
  242.         news->rightChild=vir2;
  243.     }
  244.     else
  245.     {
  246.         p=find_insertPos(root,key);
  247.         //if(p!=NULL)cout<<" insert position "<<p->key<<endl;
  248.         if(p->key>key)//在p左边插入,不用新开辟节点,用虚拟节点即可
  249.         {
  250.         news=p->leftChild;
  251.         news->color=RED;
  252.         news->key=key;
  253.         //cout<<" test left insert "<<endl;
  254.         }
  255.         else
  256.         {    
  257.         news=p->rightChild;
  258.         news->color=RED;
  259.         news->key=key;
  260.         //cout<<" test right insert "<<endl;
  261.         }
  262.         // 在news下面新建2个虚拟节点vir1,vir2,颜色为黑,值为0;
  263.         vir1=(PRBTree)new RBTree;
  264.         vir1->leftChild=NULL;
  265.         vir1->rightChild=NULL;
  266.         vir1->parent=news;
  267.         vir1->color=BLACK;
  268.         vir1->key=0;
  269.         
  270.         vir2=(PRBTree)new RBTree;
  271.         vir2->leftChild=NULL;
  272.         vir2->rightChild=NULL;
  273.         vir2->parent=news;
  274.         vir2->color=BLACK;
  275.         vir2->key=0;
  276.         news->leftChild=vir1;
  277.         news->rightChild=vir2;
  278.         rotate(news);
  279.     }
  280. }    
  281. PRBTree find_succesor(PRBTree &subroot)//首先应调用find_insertpos()找删除位置,没找到返回错误 
  282. //即subroot是找到的当前删除点,找subroot的后继,不是所有删除点都要找后继,找后继应从当前节点右子树开始,如果有的话,后继是其右子树的最左的节点
  283. {//肯定有后继,
  284.     PRBTree p,q;
  285.     p=q=NULL;
  286.     q=subroot->rightChild;
  287.     while(q->key!=0){p=q;q=q->leftChild;}
  288.     return p;
  289. }
  290. void adjust(PRBTree &root,PRBTree &subroot)
  291. {
  292.     PRBTree adjx,parent,grandparent,brother,brother_left,brother_right;
  293.     //int bicolor=1;//bicolor 用于记录调整节点是否双色,刚开始为双色
  294.     
  295.     adjx=parent=grandparent=brother=brother_left=brother_right=NULL;
  296.     adjx=subroot;//adjx标记当前双重色节点,当其为红时,推出循环
  297.      //当前节点不是根节点,肯定有双亲
  298.      //if(parent->parent!=NULL)grandparent=parent->parent;//?不用考虑grandparent,做旋转的时候自动处理
  299.      //else ROOT=parent;//双寝室根节点
  300.      
  301.      while(adjx!=ROOT&&adjx!=NULL&&adjx->color==BLACK)//红色节点直接变黑
  302.      {
  303.          parent=adjx->parent;
  304.         if(parent->leftChild==adjx)//调整节点位于双亲左边
  305.         {
  306.             if(parent->rightChild->key!=0)brother=parent->rightChild;
  307.             brother_left=brother->leftChild;//brother—left可以是虚拟节点
  308.             brother_right=brother->rightChild;
  309.             if(brother->color==RED)//第一种情况 before   brother is red, so parent is black
  310.             {
  311.                 parent->color=RED;//1-parent->color;
  312.                 brother->color=BLACK;//1-brother->color;
  313.                 LeftRotate(brother);
  314.             }
  315.             else 
  316.             {
  317.                 if(brother_right->color==BLACK)
  318.                 {
  319.                     if(brother_left->color==BLACK)//第二种情况
  320.                     {
  321.                         brother->color=RED;//brother原来是黑色,去掉一层色后应该变红
  322.                         adjx->color=BLACK;
  323.                         adjx=parent;//父节点可红或黑,若红则退出,若黑则继续循环,直至根节点
  324.                         //adjust(parent);不用递归
  325.                     }
  326.                    else //情况三 变 情况四
  327.                     {
  328.                         brother->color=RED;//1-brother->color;//brother原来是黑,左孩子原来是红
  329.                         brother_left->color=BLACK;//1-brother_left->color;
  330.                         RightRotate(brother_left);
  331.                     }
  332.                 }
  333.                 else //if(brother_right->color==RED) //情况四 可结束
  334.                 {
  335.                         brother->color=parent->color;
  336.                         parent->color=BLACK;
  337.                         brother_right->color=BLACK;
  338.                         LeftRotate(brother);//对应算法导论以parent为支点
  339.                         adjx=NULL;
  340.                }
  341.             }
  342.         }    
  343.         
  344.         else//调整节点位于双亲右边
  345.         {
  346.             if(parent->leftChild->key!=0)brother=parent->leftChild;
  347.             brother_left=brother->leftChild;//brother—left可以是虚拟节点
  348.             brother_right=brother->rightChild;
  349.             if(brother->color==RED)//第一种情况
  350.             {
  351.                 parent->color=RED;//1-parent->color;
  352.                 brother->color=BLACK;//1-brother->color
  353.                 RightRotate(brother);
  354.             }
  355.             else 
  356.             {
  357.                 if(brother_left->color==BLACK)
  358.                 {
  359.                     if(brother_right->color==BLACK)//第二种情况
  360.                     {
  361.                         brother->color=RED;
  362.                         adjx->color=BLACK;
  363.                         adjx=parent;//父节点可红或黑,若红则退出,若黑则继续循环,直至根节点
  364.                         //adjust(parent);不用递归
  365.                     }
  366.                    else //情况三 变 情况四
  367.                     {
  368.                         brother->color=RED;//;//brother原来是黑,右孩子原来是红
  369.                         brother_right->color=BLACK;//
  370.                         LeftRotate(brother_right);
  371.                     }
  372.                 }
  373.                 else //if(brother_right->color==RED) //情况四 可结束
  374.                 {
  375.                         brother->color=parent->color;
  376.                         parent->color=BLACK;
  377.                         brother_left->color=BLACK;
  378.                         RightRotate(brother);
  379.                         adjx=NULL;
  380.                }
  381.             }
  382.         }
  383.     }//while
  384.      if(adjx!=NULL)adjx->color=BLACK;//根或颜色是红都执行
  385. }
  386. PRBTree find_deletePos(PRBTree &root,KEY key)
  387. {
  388.     PRBTree p;
  389.     p=root;//q=p;
  390.     while(p->key!=0)//判断是否虚拟节点
  391.     {
  392.         if(p->key==key) return p;
  393.         else 
  394.         {
  395.             if(p->key>key)p=p->leftChild;
  396.             else p=p->rightChild;        
  397.         }
  398.     }
  399.     if(p->key==0) return NULL;//未找到删除节点
  400. }
  401. void delete_rbt(PRBTree &root,KEY key)
  402. {
  403.     PRBTree pos,suc,adj,suc_child,suc_del_child,suc_parent;
  404.     pos=suc=adj=suc_child=suc_del_child=suc_parent=NULL;
  405.     pos=find_deletePos(root,key);//pos 是要删除的节点位置,不能用寻找插入的函数
  406.     if(pos==NULL)cout<<" no such element "<<endl;
  407.     else
  408.     {
  409.         if(pos->leftChild->key==0||pos->rightChild->key==0)
  410.             suc=pos;//此时不用找后继,pos就是直接删除的节点,为方便都用suc表示
  411.         else {
  412.                 suc=find_succesor(pos);    
  413.                 pos->key=suc->key;//后继是要删除的节点,用后继值覆盖pos
  414.             }
  415. //接下来要删除suc,adj是用来调整的,suc最多只有一个孩子,且只能右孩子为虚拟节点,不对,因为suc可以等于pos,pos可以有左节点,不管怎样最多只有一个节点
  416.         
  417.         if(suc->leftChild->key!=0){suc_child=suc->leftChild;suc_del_child=suc->rightChild;}//左孩子为保留节点,有孩子为删除节点
  418.         else{
  419.              suc_del_child=suc->leftChild;//让左孩子为要删除的虚拟节点
  420.              //if(suc->rightChild->key!=0)
  421.              suc_child=suc->rightChild;//不管空不空,右孩子都为保留节点,注意右孩子可以是虚拟节点
  422.              //else {suc_child=suc->rightChild;}
  423.             }
  424.         if(suc->parent!=NULL)
  425.         {    
  426.             suc_parent=suc->parent;
  427.             if(suc->color==RED)//如果suc是红色节点不需要调整
  428.             {
  429.               if(suc_parent->leftChild==suc)suc_parent->leftChild=suc_child;
  430.               else suc_parent->rightChild=suc_child;
  431.               suc_child->parent=suc_parent;
  432.               delete suc_del_child;
  433.               delete suc;
  434.             }
  435.             else
  436.             {
  437.               if(suc_parent->leftChild==suc)suc_parent->leftChild=suc_child;
  438.               else suc_parent->rightChild=suc_child;
  439.               suc_child->parent=suc_parent;
  440.               delete suc_del_child;
  441.               delete suc;
  442.               adjust(root,suc_child);//对保留的节点进行调整
  443.             }
  444.         }
  445.         else //suc是当前根节点,其双亲为空,删除后保留节点为新的根节点
  446.         {
  447.             ROOT=suc_child;
  448.             suc_child->parent=NULL;
  449.               if(suc->color==RED)//如果suc是红色节点不需要调整
  450.             {
  451.               delete suc_del_child;
  452.               delete suc;
  453.             }
  454.             else
  455.             {
  456.               delete suc_del_child;
  457.               delete suc;
  458.               adjust(root,suc_child);//对保留的节点进行调整
  459.             }
  460.     
  461.         }
  462.     }
  463. }
  464. void Mid_Visit(PRBTree &T)
  465. {
  466.     if(T->key==0)cout<<" tree is empty "<<endl;//都删除之后 T应是一个虚拟节点
  467.     if (0 != T->key)
  468.     {
  469.         if (0 != T->leftChild->key)
  470.         {
  471.             if (T->leftChild->key > T->key)
  472.             {
  473.                 printf("wrong!\n");
  474.                 exit(-1);
  475.             }
  476.             Mid_Visit(T->leftChild);
  477.         }
  478.         cout<<T->key<<" ";
  479.         cout<<"  color is  "<<T->color;
  480.         if(T->leftChild)cout<<"   T->leftChild is "<<T->leftChild->key;
  481.         if(T->rightChild)cout<<"   T->rightChild is "<<T->rightChild->key;
  482.         if(T->parent)cout<<"   T->parent is "<<T->parent->key;
  483.         if(T==ROOT)cout<<endl<<" current root is "<<T->key<<endl;
  484.         cout<<endl;
  485.         if (0 != T->rightChild->key)
  486.         {
  487.             if (T->rightChild->key < T->key)
  488.             {
  489.                 printf("wrong\n");
  490.                 exit(-1);
  491.             }
  492.             Mid_Visit(T->rightChild);
  493.         }
  494.     }
  495.     cout<<endl;
  496. }
  497. //要通过遍历树来找所有的虚拟节点,递归遍历无法记录虚拟节点的黑色高度(除了用全局静态数组),故要用树的非递归遍历
  498. int judge_rbt(PRBTree  b){ 
  499.  PRBTree stack[100], p,q;
  500.  int top=0,height1,height2=0;  
  501.  p=b;
  502.   do{      
  503.       while (p!=NULL)
  504.       {  //扫描所有左结点
  505.        top++;
  506.        stack[top]=p;
  507.        p=p->leftChild;
  508.       }
  509.       if (top>0)
  510.       {   
  511.         p=stack[top];
  512.         top--;
  513.         //printf("%c",p->data); //访问结点,有虚拟节点,情况不一样
  514.         if(p->key==0)//计算虚拟节点黑色高度
  515.         {
  516.             height1=0;
  517.             q=p->parent;
  518.             while(q!=NULL)
  519.             {
  520.                 if(q->color==BLACK)height1++; 
  521.                 q=q->parent;
  522.             }
  523.         }
  524.         if(height2==0)height2=height1;//初始情况,只执行一次
  525.         if(height2!=height1)return 0;//当有节点高度和先前的不一样,证明不是红黑树
  526.         p=p->rightChild; //扫描右子树
  527.       }
  528.     } while(p!=NULL || top!=0);
  529.     return 1;//
  530. }
  531. int main(int argc, char *argv[])
  532. {
  533.     srand(time(NULL));
  534.     //PRBTree root = NULL;
  535.     int i,arr[N],brr[N],flag,k;
  536.     for (i = 0; i < N; i++)
  537.     {
  538.         arr[i]=rand() % 100;//arr中可能有重复元素
  539.         if(arr[i]==0)i=0;//如果产生0元素,重新产生,只有虚拟节点放0元素
  540.     }
  541.     for (i = 0,k=0;i < N; i++)//除去重复元素
  542.     {
  543.         flag=0;
  544.         for(int j=0;j<k;j++)
  545.             if(brr[j]==arr[i])flag=1;//表示当前brr[]有重复元
  546.             if(flag==0){brr[k]=arr[i];k++;}//
  547.     }    
  548.     cout<<"insert order as follow: "<<endl;
  549.     for(int j=0;j<k;j++)
  550.         cout<<brr[j]<<" ";
  551.     cout<<endl;
  552.     for(j=0;j<k;j++)
  553.     {
  554.         insert(ROOT, brr[j]);
  555.         cout<<"after insert judge whether is brt 1 means yes, 0 means no : "<<judge_rbt(ROOT)<<endl;
  556.     }
  557.     Mid_Visit(ROOT);
  558.     for(j=0;j<k;j++)
  559.     {
  560.       cout<<"after delete  "<<brr[j]<<endl;
  561.         delete_rbt(ROOT,arr[j]);
  562.         cout<<"after delete  judge whether is brt 1 means yes, 0 means no : "<<judge_rbt(ROOT)<<endl;
  563.         Mid_Visit(ROOT);
  564.     }
  565.     /*//insert(ROOT,15);
  566.     insert(ROOT,23);
  567.     insert(ROOT,10);
  568.     //insert(ROOT,18);
  569.     Mid_Visit(ROOT);
  570.     delete_rbt(ROOT,10);
  571.     cout<<"after delete 1 "<<endl;
  572.     Mid_Visit(ROOT);
  573.     cout<<" test "<<endl;
  574.     delete_rbt(ROOT,23);
  575.     cout<<"after delete 2 "<<endl;
  576.     Mid_Visit(ROOT);*/
  577.     return 0;
  578. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值