自己的红黑树-献给老杨
来源:互联网 发布: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;
}
- 自己的红黑树-献给老杨
- 献给迷茫的自己
- 献给从不更新BO的老俞
- 献给自己的第一篇......
- 献给刚入行的自己
- 献给21岁的自己
- 献给重阳节加班的自己
- 献给自己
- 献给在外奋斗的人-也献给我自己
- 最好的年华,献给奋斗的自己
- 第一帖:献给过去的自己
- 献给工作六年后自己的随想
- 献给刚出校门单纯的自己
- 献给即将步入职场的自己
- 献给即将做实习生的自己
- 献给初学安卓的自己。。Android
- 献给自己的第一篇博文
- 黑马程序员1--献给迷茫的自己
- Mysql6的auto Reconnect错误
- ListView优化三原则
- 关于gcc中内存对齐的c写法(attribute)
- 如何在flex的mxml视图中调整Imgage组件的位置
- 用Java实现FTP批量大文件上传下载
- 自己的红黑树-献给老杨
- toolTip自动消失之后不再显示的解决方法
- samba配置
- C语言实现/etc/passwd的逐行显示并打印行号和用户名
- unix/linux c 正则表达式 示例表
- ACE反应器框架1
- 微博你还能走多久?
- ABAP 剪切板操作
- 关于编译成库文件是否会智能链接的问题