#include<stdio.h>
#define Red 0
#define Black 1
#define N 100 //树的最大规模
typedef struct RBTNode
{
int key;
int color;//Black:1,Red:0
struct RBTNode *left,*right,*parent;
}RBTNode,*RBTree;
RBTNode *nil,*Root,*Node[N];
void Init() //构造叶子结点
{
nil->color=Black;
nil->left=Root;
nil->right=Root;
nil->key=-1;
Root=nil;
}
void Creat(RBTNode *T) //构造生成的结点
{
T->color=Red;
T->key=-1;
T->left=T;
T->right=T;
T->parent=T;
}
void Left_Rotate(RBTree &T,RBTNode *x) //左旋
{
RBTNode *y;
y=x->right;
x->right=y->left;
if(y->left!=nil)
y->left->parent=x;
y->parent=x->parent;
if(x->parent==nil)
Root=y;
else if(x==x->parent->left)
x->parent->left=y;
else x->parent->right=y;
y->left=x;
x->parent=y;
}
void Right_Rotate(RBTree &T,RBTNode *x) //右旋
{
RBTNode *y;
y=x->left;
x->left=y->right;
if(y->right!=nil)
y->right->parent=x;
y->parent=x->parent;
if(x->parent==nil)
Root=y;
else if(x==x->parent->left)
x->parent->left=y;
else x->parent->right=y;
y->right=x;
x->parent=y;
}
void RB_Insert_Fixup(RBTree &T,RBTNode *z) //调整插入结点
{
RBTNode *y;
while(z->parent->color==Red)
{
if(z->parent==z->parent->parent->left)
{
y=z->parent->parent->right;
if(y->color==Red)
{
z->parent->color=Black;
y->color=Black;
z->parent->parent->color=Red;
z=z->parent->parent;
}
else
{
if(z==z->parent->right)
{
z=z->parent;
Left_Rotate(T,z);
}
z->parent->color=Black;
z->parent->parent->color=Red;
Right_Rotate(T,z->parent->parent);
}
}
else
{
y=z->parent->parent->left;
if(y->color==Red)
{
z->parent->color=Black;
y->color=Black;
z->parent->parent->color=Red;
z=z->parent->parent;
}
else
{
if(z==z->parent->left)
{
z=z->parent;
Right_Rotate(T,z);
}
z->parent->color=Black;
z->parent->parent->color=Red;
Left_Rotate(T,z->parent->parent);
}
}
}
Root->color=Black;
}
void RB_Insert(RBTree &T,RBTNode *z) //插入结点
{
RBTNode *x,*y;
y=nil;
x=Root;
while(x!=nil)
{
y=x;
if(z->key<x->key)
x=x->left;
else x=x->right;
}
z->parent=y;
if(y==nil)
Root=z;
else if(z->key < y->key)
y->left=z;
else y->right=z;
z->left=nil;
z->right=nil;
z->color=Red;
RB_Insert_Fixup(T,z);
}
void RB_Mid_Visit(RBTNode *T,int &m) //中序遍历
{
if(T!=nil)
{
RB_Mid_Visit(T->left,m);//递归遍历左子树
printf("%d/t",T->key);
if(T->color==1)
printf("Black/n");
else
printf("Red/n");
m++;
RB_Mid_Visit(T->right,m);//递归遍历右子树
}
}
void main()
{
int i,M;
nil=new RBTNode;
Init();
printf("输入不超过%d的树的规模:/n",N);
scanf("%d",&M);
printf("/n**************************************/n");
printf("输入各结点的关键字:/n");
for(i=0;i<M;i++)
{
Node[i]=new RBTNode;
Creat(Node[i]);
scanf("%d",&Node[i]->key);
RB_Insert(Root,Node[i]);
}
printf("/n**************************************/n");
printf("该树为:/n");
i=0;
RB_Mid_Visit(Root,i);
printf("/n**************************************/n");
RBTNode *z;
z=new RBTNode;
Node[i]=new RBTNode;
Creat(z);
printf("插入结点:/n");
scanf("%d",&z->key);
RB_Insert(Root,z);
printf("/n**************************************/n");
printf("最终树为:/n");
i=0;
RB_Mid_Visit(Root,i);
}
附:
红黑树插入算法
u 需求分析
实现对红黑树的插入结点操作。
u 算法设计
² 设计思想
算法使用的数据结构:
结点的类型为结构体,成员变量为颜色color,关键字key,父结点 *parent,左右孩子结点 *left, *right。定义如下:
typedef struct RBTNode
{
int key;
int color;
struct RBTNode *left,*right,*parent;
}RBTNode,*RBTree;
算法基本思想:
利用插入算法个构建红黑树,每插入一个节点就调用调整算法,使插入的结点保持红黑树的性质。最终的插入操作即是在初始化后的红黑树上再插入一个结点。
² 概要设计
对每个函数的说明:
(1) void Init( );
构造并初始化叶子结点
(2) void Creat(RBTNode *T);
构造并初始化新生成结点
(3) void Left_Rotate(RBTree &T,RBTNode *x)
以x到y之间的链为支轴进行左旋操作
(4) void Right_Rotate(RBTree &T,RBTNode *x);
以x到y之间的链为支轴进行右旋操作
(5)void RB_Insert_Fixup(RBTree &T,RBTNode *z);
对新插入的结点z进行颜色与位置的调整,使调整后的树满足红黑性质
(6)void RB_Insert(RBTree &T,RBTNode *z);
在树T中插入新结点z,再调用RBInsertFixup算法对树进行调整,以保持树的红黑性质
(7)void RB_Mid_Visit(RBTNode *T,int &m)
中序遍历树T并按关键字大小顺序输出各结点的关键字及颜色
² 详细设计
主要算法思想及描述:
#include<stdio.h>
#define Red 0
#define Black 1
#define N 100
#define black 0 //0代表黑色
#define red 1 //1代表红色
#define MAX 100 //树的最大规模
typedef struct RBTNode
{
int key;
int color;//Black:1,Red:0
struct RBTNode *left,*right,*parent;
}RBTNode,*RBTree;
RBTNode *nil,*Root,*Node[N];
void Init();//初始化叶子结点
void Initialize(RBTNode *T);//初始化新生成结点
void Left_Rotate(RBTree &T,RBTNode *x);//左旋
void Right_Rotate(RBTree &T,RBTNode *x);//右旋
void RB_Insert(RBTree &T,RBTNode *z);//插入结点
void RB_Insert_Fixup(RBTree &T,RBTNode *z);//调整结点算法
void RB_Mid_Visit(RBTNode *T,int &m);//中序遍历树
(1)main( )执行各种初始化工作,并对每个新生成结点调用插入算法,生成红黑树,之后调用中序遍历算法输出各个内结点,然后完成插入操作。设计如下:
void main()
{
int i,M;
nil=new RBTNode;
Init();
printf("输入不超过%d的树的规模:/n",N);
scanf("%d",&M);
printf("/n**************************************/n");
printf("输入各结点的关键字:/n");
for(i=0;i<M;i++)
{
Node[i]=new RBTNode;
Creat(Node[i]);
scanf("%d",&Node[i]->key);
RB_Insert(Root,Node[i]);
}
printf("/n**************************************/n");
printf("该树为:/n");
i=0;
RB_Mid_Visit(Root,i);
printf("/n**************************************/n");
RBTNode *z;
z=new RBTNode;
Node[i]=new RBTNode;
Creat(z);
printf("插入结点:/n");
scanf("%d",&z->key);
RB_Insert(Root,z);
printf("/n**************************************/n");
printf("最终树为:/n");
i=0;
RB_Mid_Visit(Root,i);
}
(2)函数Init()执行初始化叶子结点的任务,叶子结点的颜色为黑色,左右孩子均为根结点。初始根指向叶子结点,即为空树。设计如下:
void Init() //构造叶子结点
{
nil->color=Black;
nil->left=Root;
nil->right=Root;
nil->key=-1;
Root=nil;
}
(3)函数Initialize(RBTNode *T)对新生成的结点进行初始化,结点颜色为红色,以保证插入时不改变黑高,结点的关键字为-1,左右孩子均指向自身。设计如下:
void Creat(RBTNode *T) //构造生成的结点
{
T->color=Red;
T->key=-1;
T->left=T;
T->right=T;
T->parent=T;
}
(4)函数void Left_Rotate(RBTree &T,RBTNode *x)对结点x执行左旋操作,设计如下:
void Left_Rotate(RBTree &T,RBTNode *x) //左旋
{
RBTNode *y;
y=x->right;
x->right=y->left;
if(y->left!=nil)
y->left->parent=x;
y->parent=x->parent;
if(x->parent==nil)
Root=y;
else if(x==x->parent->left)
x->parent->left=y;
else x->parent->right=y;
y->left=x;
x->parent=y;
}
(5)函数void Right_Rotate(RBTree &T,RBTNode *x)对结点x执行左旋操作。设计如下:
void Right_Rotate(RBTree &T,RBTNode *x) //右旋
{
RBTNode *y;
y=x->left;
x->left=y->right;
if(y->right!=nil)
y->right->parent=x;
y->parent=x->parent;
if(x->parent==nil)
Root=y;
else if(x==x->parent->left)
x->parent->left=y;
else x->parent->right=y;
y->right=x;
x->parent=y;
}
(6)函数void RB_Insert_Fixup(RBTree &T,RBTNode *z)对插入结点z后的树进行颜色与位置的调整,使新得到的树仍是一棵红黑树。设计如下:
void RB_Insert_Fixup(RBTree &T,RBTNode *z) //调整插入结点
{
RBTNode *y;
while(z->parent->color==Red)
{
if(z->parent==z->parent->parent->left)
{
y=z->parent->parent->right;
if(y->color==Red)
{
z->parent->color=Black;
y->color=Black;
z->parent->parent->color=Red;
z=z->parent->parent;
}
else
{
if(z==z->parent->right)
{
z=z->parent;
Left_Rotate(T,z);
}
z->parent->color=Black;
z->parent->parent->color=Red;
Right_Rotate(T,z->parent->parent);
}
}
else
{
y=z->parent->parent->left;
if(y->color==Red)
{
z->parent->color=Black;
y->color=Black;
z->parent->parent->color=Red;
z=z->parent->parent;
}
else
{
if(z==z->parent->left)
{
z=z->parent;
Right_Rotate(T,z);
}
z->parent->color=Black;
z->parent->parent->color=Red;
Left_Rotate(T,z->parent->parent);
}
}
}
Root->color=Black;
}
(7)函数void RB_Insert(RBTree &T,RBTNode *z)是树T中插入结点z,并调用结点调整函数void RB_Insert_Fixup(RBTree &T,RBTNode *z)调整插入结点后的树中结点的位置与颜色,使之保持红黑树的性质。设计如下:
void RB_Insert(RBTree &T,RBTNode *z) //插入结点
{
RBTNode *x,*y;
y=nil;
x=Root;
while(x!=nil)
{
y=x;
if(z->key<x->key)
x=x->left;
else x=x->right;
}
z->parent=y;
if(y==nil)
Root=z;
else if(z->key < y->key)
y->left=z;
else y->right=z;
z->left=nil;
z->right=nil;
z->color=Red;
RB_Insert_Fixup(T,z);
}
(8)函数void RB_Mid_Visit(RBTNode *T,int &m)对红黑树进行中序遍历,按关键字的大小顺序输出各个结点的值与颜色。设计如下:
void RB_Mid_Visit(RBTNode *T,int &m) //中序遍历
{
if(T!=nil)
{
RB_Mid_Visit(T->left,m);//递归遍历左子树
printf("%d/t",T->key);
if(T->color==1)
printf("Black/n");
else
printf("Red/n");
m++;
RB_Mid_Visit(T->right,m);//递归遍历右子树
}
}
u 测试数据及结果
测试数据:
Ø 树的规模:5
原树结点关键字:23,2,56,89,3
插入结点关键字:34
v 结果如下:
输入不超过100的树的规模:
5
**************************************
输入各结点的关键字:
23
2
56
89
3
**************************************
该树为:
2 Black
3 Red
23 Black
56 Black
89 Red
**************************************
插入结点:
45
**************************************
最终树为:
2 Black
3 Red
23 Black
45 Red
56 Black
89 Red
Press any key to continue
Ø 树的规模:10
原树结点关键字:23,11,5,34,7,38,6,9,26,98
插入结点关键字:34
v 结果如下:
输入不超过100的树的规模:
10
**************************************
输入各结点的关键字:
23
11
5
34
7
38
6
9
26
98
**************************************
该树为:
5 Black
6 Red
7 Black
9 Red
11 Black
23 Black
26 Red
34 Red
38 Black
98 Red
**************************************
插入结点:
10
**************************************
最终树为:
5 Black
6 Red
7 Red
9 Black
10 Red
11 Black
23 Black
26 Red
34 Red
38 Black
98 Red
Press any key to continue
u 时间及空间性能分析:
时间分析:函数RBInsertFixup(RBTree &T,RBTNode *z)的运行时间为O(lgn);
函数RBInsert(RBNode *T,RBNode *z)的运行时间为O(lgn);
因此对于n个结点的红黑树,总的时间复杂度为O(nlgn)。
空间复杂度为O(n)。