/* 作者:田帥
學校:**大學
版本:紅/黑樹狀結構初始版本
*/
#include"stdio.h"
#include"malloc.h"
#define MIN -99999999 //不要加等號
#define MAX 99999999
struct node
{
long key;
char color;
struct node *p;
struct node *leftChild;
struct node *rightChild;
};
node *nil,*root;//建立根節點和葉子節點
int printnode=0;
node *CreateNode(int key);
void RB_insert_fixUp(node *T,node *z);
void nil_create();//葉子節點建立
void RB_insert(node *T,node *z);//弄演算法導論上非遞迴的吧
void left_rotate(node *T,node *z);//向左旋轉
void right_rotate(node *T,node *z);
void PrintRBTree(node *T);//輸出樹
void nil_create()//葉子節點建立
{
nil=(node *)malloc(sizeof(node));
root=(node *)malloc(sizeof(node));
nil->key=MIN;
nil->color='B';
//nil->p=NULL;//這裡注意
nil->leftChild=nil;
nil->rightChild=nil;
root=nil;
}
node *CreateNode(int key)
{
node *x = (node *)malloc(sizeof(node));
x->color ='R';
x->key = key;
x->leftChild = nil;
x->rightChild = nil;
x->p = NULL;
return x;
}
void RB_insert(node *T,node *z)//弄演算法導論上非遞迴的吧
{
node *x,*y;//y用來記錄父節點
x=root;//這裡應該是 根節點 跟形式參數重複 會造成錯誤
y=nil;
while(x!=nil)//x為要插入的位置de父節點 y為x的父節點
{
y=x;
if(x->key>z->key)
x=x->leftChild;
else
x=x->rightChild;
}
z->p=y;
if(y==nil)//初始化 插入到空樹種
root=z;
else if(z->key<y->key)
y->leftChild=z;
else
y->rightChild=z;
z->leftChild=nil;
z->rightChild=nil;
z->color='R';
RB_insert_fixUp(T,z);
}
void RB_insert_fixUp(node *T,node *z)
{
node *y;
while(z->p->color=='R')//插入節點 是紅節點 如果父節點也是紅節點 則需要調整
{
if(z->p==z->p->p->leftChild)//插入的節點的父節點 是祖父節點的左孩子
{
y=z->p->p->rightChild;//祖父節點的右孩子
if(y->color=='R')//二叔是 紅色的O(∩_∩)O哈哈~
{
z->p->color='B';
y->color='B';
z->p->p->color='R';
z=z->p->p;
}
else
{//這個地方一定要加上 {
if(z==z->p->rightChild)//二叔是黑色 且 要插入的節點是右孩子
{
z=z->p;
left_rotate(T,z);
}
z->p->color='B';//二叔是黑色 且要插入的節點是左孩子
z->p->p->color='R';
// z->p->p->color='R'; //???????????????????????????
right_rotate(T,z->p->p);
}
}
else//插入的節點的父節點 是祖父節點的右孩子
{
y=z->p->p->leftChild;//祖父節點的左孩子
if(y->color=='R')//二叔是 紅色的O(∩_∩)O哈哈~
{
z->p->color='B';
y->color='B';
z->p->p->color='R';
z=z->p->p;//???????
}
else
{
if(z==z->p->leftChild)//二叔是黑色 且 要插入的節點是左孩子
{
z=z->p;
right_rotate(T,z);
}
z->p->color='B';//二叔是黑色 且要插入的節點是右孩子
z->p->p->color='R';
left_rotate(T,z->p->p);
}
}
}
root->color='B';//這裡不要落下!!!
}
void left_rotate(node *T,node *z)//向左旋轉
{
node *y;
y=z->rightChild;//讓y 為要旋轉的節點的右子樹
z->rightChild=y->leftChild;
if(y->leftChild!=nil)
y->leftChild->p=z;
y->p=z->p;//將要旋轉節點切下
if(z->p==nil)
root=y;
else if(z==z->p->leftChild)//要旋轉節點是 其父節點左孩子
z->p->leftChild=y;
else//要旋轉節點是 其父節點右孩子
z->p->rightChild=y;
y->leftChild=z;//將要旋轉節點掛到 代替它的孩子的左子樹上
z->p=y;
}
void right_rotate(node *T,node *z)
{
node *y;
y=z->leftChild;//讓y 為要旋轉的節點的左子樹
z->leftChild=y->rightChild;
if(y->rightChild!=nil)
y->rightChild->p=z;
y->p=z->p;//將要旋轉節點切下
if(z->p==nil)
root=y;
else if(z==z->p->leftChild)//要旋轉節點是 其父節點左孩子
z->p->leftChild=y;
else//要旋轉節點是 其父節點右孩子
z->p->rightChild=y;
y->rightChild=z;//將要旋轉節點掛到 代替它的孩子的左子樹上
z->p=y;
}
void PrintRBTree(node *T)
{
int i;
if(T != nil)
{
for(i = 0; i <= printnode;i++)
printf(" ");
printf("(%d",T->key);
if(T->color == 'B')
printf("B,\n");
else
printf("R,\n");
printnode++;
PrintRBTree(T->leftChild);
PrintRBTree(T->rightChild);
printnode--;
for(int j = 0; j <= printnode;j++)
printf(" ");
printf("),\n");
}
else
{
for(int i = 0; i <= printnode;i++)
printf(" ");
printf("Nil,\n");
}
}
void INORDER_TREE_WALK(struct node* x) //中根遍曆
{
//printf("%ld %c ",x->key,x->color); //debug 先根遍曆
if(x->leftChild!=nil)
INORDER_TREE_WALK(x->leftChild);
printf("%ld %c ",x->key,x->color);
if(x->rightChild!=nil)
INORDER_TREE_WALK(x->rightChild);
}
int main()
{ //long a[11]={4,1,3,2,16,9,10,14,8,7};
//long a[10]={10,9,8,7,6,5,4,3,2,1};
// long a[10]={1,2,3,4,5,6,7,8,9,10};
// long a[]={1,2,3,4,5,6,7,8,9,10};//這個可以
long a[]={4,1,3,2,16,9,10,14,8,7};//這個不可以
node *z[11];
nil_create();
// nil=(node *)malloc(sizeof(node));
// nil=nil_create();
printf(" 1111111");
for(int j = 0; j <10; j++)
{
printf(" 222222 ");
z[j]=CreateNode(a[j]);
RB_insert(root,z[j]);
}
printf(" 222222 ");
INORDER_TREE_WALK(root);
// PrintRBTree(root);
return 0;
}
出現的錯誤及調試方法:
總是到insert_fix_up時候出現錯誤;原因是 第三種情況 要寫在 if(y.color=='R') else{ if() ; ********} 不要忘記在else 之後加上 大括弧