自己的红黑树-献给老杨

来源:互联网 发布:ubuntu 14.04 u盘安装 编辑:程序博客网 时间:2024/06/07 07:14
 


#include<iostream>
#include<time.h>
using namespace std;
typedef int KEY;
#define N 10
enum NODECOLOR
{
    BLACK        = 0,
    RED          = 1
};

typedef struct RBTree
{
    struct        RBTree *parent;
    struct      RBTree *leftChild, *rightChild;
    KEY            key;
    NODECOLOR   color;
}RBTree, *PRBTree;
PRBTree ROOT;//根节点是ROOT
void Mid_Visit(PRBTree &T);

void LeftRotate(PRBTree &subroot)
{
 //cout<<" left rotate "<<endl;
 PRBTree grandParent,parent,leftChild;//,rightChild;
 grandParent=NULL;parent=NULL;leftChild=NULL;
 if(subroot!=ROOT&&subroot!=NULL)parent=subroot->parent;//根节点是ROOT,
 if(parent!=ROOT&&parent!=NULL)grandParent=parent->parent;
 if(subroot->leftChild!=NULL)leftChild=subroot->leftChild;//如果subroot不为空,两个孩子都不为空,至多有虚拟节点,同样参与装换
 //if(subroot->rightChild!=NULL)rightChild=subroot->rightChild;
 if(grandParent!=NULL)
 {
  if(grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
  else grandParent->rightChild=subroot;//grandparent不空,一定有左孩子,或右孩子并且至少有一个不是虚拟节点
 /*if(grandParent->leftChild!=NULL&&grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
 else if(grandParent->rightChild->key==parent->key)grandParent->rightChild=subroot;//有问题 if语句不成立条件*/
 }
 else//if  grandparent is null, then quadain parent is ROOT ,after left rotate, subroot becomes ROOT
 {   // if quadain parent is root then change cannot happened for its color is balck.so this sentence will never be executed
  //此判断不对,当进行一次有旋转后,在进行的左旋转就针对当前节点没有grandparent,而只有parent,而此时grandparent初始化为空了
  ROOT=subroot;subroot->parent=NULL;subroot->color=BLACK;//cout<<" try judgement "<<endl;
 }
 //if(grandParent->leftChild!=NULL&&grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
 //else if(grandParent->rightChild->key==parent->key)grandParent->rightChild=subroot;//有问题 if语句不成立条件
 subroot->parent=grandParent;//2 grandparent可为空
 parent->rightChild=leftChild;//1
 if(leftChild!=NULL)leftChild->parent=parent;//2
 parent->parent=subroot;//1
 subroot->leftChild=parent;//2
 //变颜色
 //parent->color=RED;
 //subroot->color=BLACK;
}
void RightRotate(PRBTree &subroot)
{
 //cout<<" right rotate "<<endl;
 PRBTree grandParent,parent,rightChild;//leftChild;,
 grandParent=NULL;parent=NULL;rightChild=NULL;
 if(subroot!=ROOT&&subroot!=NULL)parent=subroot->parent;//根节点是ROOT,
 if(parent!=ROOT&&parent!=NULL)grandParent=parent->parent;
 if(subroot->rightChild!=NULL)rightChild=subroot->rightChild;
 //if(subroot->rightChild!=NULL)rightChild=subroot->rightChild;
 if(grandParent!=NULL)
 {
  if(grandParent->leftChild!=NULL&&grandParent->leftChild->key==parent->key)grandParent->leftChild=subroot;//1
 else if(grandParent->rightChild->key==parent->key)grandParent->rightChild=subroot;//有问题 if语句不成立条件
 }
 else//if  grandparent is null, then quadain parent is ROOT ,after right rotate, subroot baecomes ROOT
 {
  ROOT=subroot;subroot->parent=NULL;subroot->color=BLACK;
 }
 subroot->parent=grandParent;//2

 parent->leftChild=rightChild;//1
 if(rightChild!=NULL)rightChild->parent=parent;//2

 parent->parent=subroot;//1
 subroot->rightChild=parent;//2
 //变颜色
 //parent->color=RED;
 //subroot->color=BLACK;
}
int check(PRBTree subroot)//subroot is new added node三个节点相连有四种情况.1.2.3.4,四个节点也有四种情况5,每种和三个节点有对应关系
{
 PRBTree parent,grandparent;
 parent=NULL;grandparent=NULL;//指针都要初始化
 if(subroot!=NULL&&subroot->parent!=NULL)parent=subroot->parent;
 //cout<<" in test 12 "<<endl;
  if(parent!=NULL&&parent->parent!=NULL)grandparent=parent->parent;
 //cout<<" in test 13 "<<endl;
 if(parent!=NULL&&parent->color==BLACK)return 0;//不用变换
 else
 {
  //cout<<" in test 14 "<<endl;
  if(grandparent!=NULL)//grandparent不为空,则两个孩子也不为空
  {
   if(grandparent->leftChild->key!=0&&grandparent->leftChild->key==parent->key)
   {
    //cout<<" in test 15 "<<endl;
   if(grandparent->rightChild->key!=0&&grandparent->rightChild->color==RED)//属于四个节点情况,四种情况一样处理,返回5
   {
    //只有右节点不是虚拟节点时上面判断才有意义
     return 5;
    //cout<<" in test 16 "<<endl;
   }
   else//属于三个节点情况
   {
    //cout<<" in test 17 "<<endl;
    if(parent->leftChild==subroot)//parent肯定不是虚拟节点,
     return 1;
    else return 2;
   }
   }
   else
   {
    //cout<<" in test 18 "<<endl;
   if(grandparent->leftChild->key!=0&&grandparent->leftChild->color==RED)//属于四个节点情况,四种情况一样处理,返回5
   {    
    return 5;
   }
   else//属于三个节点情况
   {
    //cout<<" in test 19 "<<endl;
    if(parent->leftChild==subroot)
     return 4;
    else return 3;
   }
   }
  }
  else return 0;//当前只有两个节点
 }
}
PRBTree find_insertPos(PRBTree &root,KEY key)//寻找插入位置,二分查找
{
 PRBTree p,q;
 p=root;q=p;
 while(q->key!=0)//判断是否虚拟节点
 {
  if(p->key>key)
  {
   q=p->leftChild;
   if(q->key!=0)p=q;
  }
  else
  {
   q=p->rightChild;
   if(q->key!=0)p=q;
  }
 }
 return p;
}

void rotate(PRBTree &subroot)//针对新插入的节点
{
 //cout<<" in rotate "<<endl;
 PRBTree parent,grandparent;
 parent=NULL;grandparent=NULL;
 if(subroot!=NULL&&subroot->parent!=NULL)parent=subroot->parent;
 //cout<<" in test 10 "<<endl;
  if(parent!=NULL&&parent->parent!=NULL)grandparent=parent->parent;
 
 //cout<<" in test 11 "<<endl;
 switch(check(subroot))
 {
  //cout<<" in check "<<endl;
 case 5://有四种情况
  //cout<<" test check 5 "<<endl;
  if(grandparent!=ROOT)grandparent->color=RED;
  else grandparent->color=BLACK;
  grandparent->leftChild->color=BLACK;
  grandparent->rightChild->color=BLACK;
  //check(grandparent);
  //if(grandparent-parent!=NULL)
  rotate(grandparent);//如果返回0,什么也不做
 break;
 case 1:
  //cout<<" test check 1 "<<endl;
  RightRotate(parent);
  parent->color=BLACK;
  //grandparent->color=RED;
  if(grandparent!=ROOT)grandparent->color=RED;
  else grandparent->color=BLACK;
  //subroot->color=BLACK;
 break;
 case 2:
  //cout<<" test check 2 "<<endl;
 LeftRotate(subroot);
 //cout<<"after leftrotate "<<endl;
 //Mid_Visit(ROOT);//ROOT为根节点
 RightRotate(subroot);
 //cout<<"test whether rightrotate  "<<endl;
 subroot->color=BLACK;
 //if(grandparent!=ROOT)grandparent->color=RED;
 if(grandparent!=ROOT)grandparent->color=RED;
  else grandparent->color=BLACK;
 break;
 case 3:
  //cout<<" test check 3 "<<endl;
 LeftRotate(parent);
 parent->color=BLACK;
 //grandparent->color=RED;
 if(grandparent!=ROOT)grandparent->color=RED;
  else grandparent->color=BLACK;
 break;
 case 4:
  //cout<<" test check 4 "<<endl;
 RightRotate(subroot);
 //LeftRotate(parent);//此时parent是subroot的右孩子
 LeftRotate(subroot);
 subroot->color=BLACK;
 if(grandparent!=ROOT)grandparent->color=RED;
 break;
 case 0:
  //cout<<" test check 0 "<<endl;
  ;
 }
}
void insert(PRBTree &root,KEY key)
{
 PRBTree p,q,news,vir1,vir2;
  p=NULL;q=NULL;news=NULL;
 if(root==NULL)
 {
  news=(PRBTree)new RBTree;//1,新建当前节点
  news->leftChild=NULL;
  news->rightChild=NULL;
  news->parent=NULL;//根节点无父节点
  news->color=BLACK;//根节点为黑色节点
  news->key=key;
  root=news;//root返回的也是根
  ROOT=news;
  // 新建2个虚拟节点vir1,vir2,颜色为黑,值为0;
  vir1=(PRBTree)new RBTree;
  vir1->leftChild=NULL;
  vir1->rightChild=NULL;
  vir1->parent=news;
  vir1->color=BLACK;
  vir1->key=0;
  
  vir2=(PRBTree)new RBTree;
  vir2->leftChild=NULL;
  vir2->rightChild=NULL;
  vir2->parent=news;
  vir2->color=BLACK;
  vir2->key=0;
  news->leftChild=vir1;
  news->rightChild=vir2;
 }
 else
 {
  p=find_insertPos(root,key);
  //if(p!=NULL)cout<<" insert position "<<p->key<<endl;
  if(p->key>key)//在p左边插入,不用新开辟节点,用虚拟节点即可
  {
  news=p->leftChild;
  news->color=RED;
  news->key=key;
  //cout<<" test left insert "<<endl;
  }
  else
  { 
  news=p->rightChild;
  news->color=RED;
  news->key=key;
  //cout<<" test right insert "<<endl;
  }
  // 在news下面新建2个虚拟节点vir1,vir2,颜色为黑,值为0;
  vir1=(PRBTree)new RBTree;
  vir1->leftChild=NULL;
  vir1->rightChild=NULL;
  vir1->parent=news;
  vir1->color=BLACK;
  vir1->key=0;
  
  vir2=(PRBTree)new RBTree;
  vir2->leftChild=NULL;
  vir2->rightChild=NULL;
  vir2->parent=news;
  vir2->color=BLACK;
  vir2->key=0;
  news->leftChild=vir1;
  news->rightChild=vir2;

  rotate(news);
 }

PRBTree find_succesor(PRBTree &subroot)//首先应调用find_insertpos()找删除位置,没找到返回错误
//即subroot是找到的当前删除点,找subroot的后继,不是所有删除点都要找后继,找后继应从当前节点右子树开始,如果有的话,后继是其右子树的最左的节点
{//肯定有后继,
 PRBTree p,q;
 p=q=NULL;
 q=subroot->rightChild;
 while(q->key!=0){p=q;q=q->leftChild;}
 return p;
}

void adjust(PRBTree &root,PRBTree &subroot)
{
 PRBTree adjx,parent,grandparent,brother,brother_left,brother_right;
 //int bicolor=1;//bicolor 用于记录调整节点是否双色,刚开始为双色
 
 adjx=parent=grandparent=brother=brother_left=brother_right=NULL;
 adjx=subroot;//adjx标记当前双重色节点,当其为红时,推出循环
  //当前节点不是根节点,肯定有双亲
  //if(parent->parent!=NULL)grandparent=parent->parent;//?不用考虑grandparent,做旋转的时候自动处理
  //else ROOT=parent;//双寝室根节点
 
  while(adjx!=ROOT&&adjx!=NULL&&adjx->color==BLACK)//红色节点直接变黑
  {
   parent=adjx->parent;
  if(parent->leftChild==adjx)//调整节点位于双亲左边
  {
   if(parent->rightChild->key!=0)brother=parent->rightChild;
   brother_left=brother->leftChild;//brother—left可以是虚拟节点
   brother_right=brother->rightChild;
   if(brother->color==RED)//第一种情况 before   brother is red, so parent is black
   {
    parent->color=RED;//1-parent->color;
    brother->color=BLACK;//1-brother->color;
    LeftRotate(brother);
   }
   else
   {
    if(brother_right->color==BLACK)
    {
     if(brother_left->color==BLACK)//第二种情况
     {
      brother->color=RED;//brother原来是黑色,去掉一层色后应该变红
      adjx->color=BLACK;
      adjx=parent;//父节点可红或黑,若红则退出,若黑则继续循环,直至根节点
      //adjust(parent);不用递归
     }
       else //情况三 变 情况四
     {
      brother->color=RED;//1-brother->color;//brother原来是黑,左孩子原来是红
      brother_left->color=BLACK;//1-brother_left->color;
      RightRotate(brother_left);
     }
    }
    else //if(brother_right->color==RED) //情况四 可结束
    {
      brother->color=parent->color;
      parent->color=BLACK;
      brother_right->color=BLACK;
      LeftRotate(brother);//对应算法导论以parent为支点
      adjx=NULL;
      }
   }
  } 
  
  else//调整节点位于双亲右边
  {
   if(parent->leftChild->key!=0)brother=parent->leftChild;
   brother_left=brother->leftChild;//brother—left可以是虚拟节点
   brother_right=brother->rightChild;
   if(brother->color==RED)//第一种情况
   {
    parent->color=RED;//1-parent->color;
    brother->color=BLACK;//1-brother->color
    RightRotate(brother);
   }
   else
   {
    if(brother_left->color==BLACK)
    {
     if(brother_right->color==BLACK)//第二种情况
     {
      brother->color=RED;
      adjx->color=BLACK;
      adjx=parent;//父节点可红或黑,若红则退出,若黑则继续循环,直至根节点
      //adjust(parent);不用递归
     }
       else //情况三 变 情况四
     {
      brother->color=RED;//;//brother原来是黑,右孩子原来是红
      brother_right->color=BLACK;//
      LeftRotate(brother_right);
     }
    }
    else //if(brother_right->color==RED) //情况四 可结束
    {
      brother->color=parent->color;
      parent->color=BLACK;
      brother_left->color=BLACK;
      RightRotate(brother);
      adjx=NULL;
      }
   }
  }
 }//while
  if(adjx!=NULL)adjx->color=BLACK;//根或颜色是红都执行
}
PRBTree find_deletePos(PRBTree &root,KEY key)
{
 PRBTree p;
 p=root;//q=p;
 while(p->key!=0)//判断是否虚拟节点
 {
  if(p->key==key) return p;
  else
  {
   if(p->key>key)p=p->leftChild;
   else p=p->rightChild;  
  }
 }
 if(p->key==0) return NULL;//未找到删除节点
}
void delete_rbt(PRBTree &root,KEY key)
{
 PRBTree pos,suc,adj,suc_child,suc_del_child,suc_parent;
 pos=suc=adj=suc_child=suc_del_child=suc_parent=NULL;
 pos=find_deletePos(root,key);//pos 是要删除的节点位置,不能用寻找插入的函数
 if(pos==NULL)cout<<" no such element "<<endl;
 else
 {
  if(pos->leftChild->key==0||pos->rightChild->key==0)
   suc=pos;//此时不用找后继,pos就是直接删除的节点,为方便都用suc表示
  else {
    suc=find_succesor(pos); 
    pos->key=suc->key;//后继是要删除的节点,用后继值覆盖pos
   }
//接下来要删除suc,adj是用来调整的,suc最多只有一个孩子,且只能右孩子为虚拟节点,不对,因为suc可以等于pos,pos可以有左节点,不管怎样最多只有一个节点
  
  if(suc->leftChild->key!=0){suc_child=suc->leftChild;suc_del_child=suc->rightChild;}//左孩子为保留节点,有孩子为删除节点
  else{
    suc_del_child=suc->leftChild;//让左孩子为要删除的虚拟节点
    //if(suc->rightChild->key!=0)
    suc_child=suc->rightChild;//不管空不空,右孩子都为保留节点,注意右孩子可以是虚拟节点
    //else {suc_child=suc->rightChild;}
   }
  if(suc->parent!=NULL)
  { 
   suc_parent=suc->parent;
   if(suc->color==RED)//如果suc是红色节点不需要调整
   {
     if(suc_parent->leftChild==suc)suc_parent->leftChild=suc_child;
     else suc_parent->rightChild=suc_child;
     suc_child->parent=suc_parent;
     delete suc_del_child;
     delete suc;
   }
   else
   {
     if(suc_parent->leftChild==suc)suc_parent->leftChild=suc_child;
     else suc_parent->rightChild=suc_child;
     suc_child->parent=suc_parent;
     delete suc_del_child;
     delete suc;
     adjust(root,suc_child);//对保留的节点进行调整
   }
  }
  else //suc是当前根节点,其双亲为空,删除后保留节点为新的根节点
  {
   ROOT=suc_child;
   suc_child->parent=NULL;
     if(suc->color==RED)//如果suc是红色节点不需要调整
   {
     delete suc_del_child;
     delete suc;
   }
   else
   {
     delete suc_del_child;
     delete suc;
     adjust(root,suc_child);//对保留的节点进行调整
   }
 
  }
 }
}
void Mid_Visit(PRBTree &T)
{
 if(T->key==0)cout<<" tree is empty "<<endl;//都删除之后 T应是一个虚拟节点
    if (0 != T->key)
    {
        if (0 != T->leftChild->key)
        {
            if (T->leftChild->key > T->key)
            {
                printf("wrong!\n");
                exit(-1);
            }
            Mid_Visit(T->leftChild);
        }
        cout<<T->key<<" ";
  cout<<"  color is  "<<T->color;
  if(T->leftChild)cout<<"   T->leftChild is "<<T->leftChild->key;
  if(T->rightChild)cout<<"   T->rightChild is "<<T->rightChild->key;
  if(T->parent)cout<<"   T->parent is "<<T->parent->key;
  if(T==ROOT)cout<<endl<<" current root is "<<T->key<<endl;
  cout<<endl;
        if (0 != T->rightChild->key)
        {
            if (T->rightChild->key < T->key)
            {
                printf("wrong\n");
                exit(-1);
            }
            Mid_Visit(T->rightChild);
        }
    }
 cout<<endl;
}
//要通过遍历树来找所有的虚拟节点,递归遍历无法记录虚拟节点的黑色高度(除了用全局静态数组),故要用树的非递归遍历
int judge_rbt(PRBTree  b){
 PRBTree stack[100], p,q;
 int top=0,height1,height2=0; 
 p=b;
  do{     
   while (p!=NULL)
   {  //扫描所有左结点
    top++;
    stack[top]=p;
    p=p->leftChild;
   }
   if (top>0)
   {  
     p=stack[top];
  top--;
  //printf("%c",p->data); //访问结点,有虚拟节点,情况不一样
  if(p->key==0)//计算虚拟节点黑色高度
  {
   height1=0;
   q=p->parent;
   while(q!=NULL)
   {
    if(q->color==BLACK)height1++;
    q=q->parent;
   }
  }
  if(height2==0)height2=height1;//初始情况,只执行一次
  if(height2!=height1)return 0;//当有节点高度和先前的不一样,证明不是红黑树
  p=p->rightChild; //扫描右子树
   }
 } while(p!=NULL || top!=0);
 return 1;//
}

int main(int argc, char *argv[])
{
    srand(time(NULL));
    //PRBTree root = NULL;
    int i,arr[N],brr[N],flag,k;
    for (i = 0; i < N; i++)
    {
        arr[i]=rand() % 100;//arr中可能有重复元素
  if(arr[i]==0)i=0;//如果产生0元素,重新产生,只有虚拟节点放0元素
 }
 for (i = 0,k=0;i < N; i++)//除去重复元素
    {
  flag=0;
        for(int j=0;j<k;j++)
   if(brr[j]==arr[i])flag=1;//表示当前brr[]有重复元
   if(flag==0){brr[k]=arr[i];k++;}//
 } 
 cout<<"insert order as follow: "<<endl;
 for(int j=0;j<k;j++)
  cout<<brr[j]<<" ";
 cout<<endl;
 for(j=0;j<k;j++)
 {
  insert(ROOT, brr[j]);
  cout<<"after insert judge whether is brt 1 means yes, 0 means no : "<<judge_rbt(ROOT)<<endl;
 }
 Mid_Visit(ROOT);
 for(j=0;j<k;j++)
 {
   cout<<"after delete  "<<brr[j]<<endl;
  delete_rbt(ROOT,arr[j]);
  cout<<"after delete  judge whether is brt 1 means yes, 0 means no : "<<judge_rbt(ROOT)<<endl;
     Mid_Visit(ROOT);
 }
 /*//insert(ROOT,15);
 insert(ROOT,23);
 insert(ROOT,10);
 //insert(ROOT,18);
    Mid_Visit(ROOT);
 delete_rbt(ROOT,10);
 cout<<"after delete 1 "<<endl;
 Mid_Visit(ROOT);
 cout<<" test "<<endl;
 delete_rbt(ROOT,23);
 cout<<"after delete 2 "<<endl;
 Mid_Visit(ROOT);*/
    return 0;
}

 

原创粉丝点击