您的位置:首页 > 编程语言 > C语言/C++

红黑树插入算法实现

2015-11-06 21:16 309 查看
</pre><p>参考文件:  <a target=_blank href="http://www.soft568.com/info/detail/4-11258.html">http://www.soft568.com/info/detail/4-11258.html</a></p><p align="left"><span style="color:#666666;">在</span><span style="color:#666666;">VC</span><span style="color:#666666;">环境下编译。主体语言是</span><span style="color:#666666;">C</span><span style="color:#666666;">,用到了点</span><span style="color:#666666;">C++</span><span style="color:#666666;">语法。</span></p><p align="left"><span style="color:#666666;"> </span></p><p align="left"><span style="color:#666666;">由于红黑树中的元素必须各不相同,定义了一个时间复杂度仅为</span><span style="color:#666666;">O</span><span style="color:#666666;">(</span><span style="color:#666666;">n</span><span style="color:#666666;">)的随机数产生函数:</span></p><p align="left"><span style="color:#666666;">void Random(int *A, int max, int length);</span></p><p align="left"><span style="color:#666666;">该函数能返回一个长度为</span><span style="color:#666666;">length,</span><span style="color:#666666;">元素随机分布在</span><span style="color:#666666;">0~max</span><span style="color:#666666;">之间的数组</span><span style="color:#666666;">A</span><span style="color:#666666;">。</span></p><p align="left"><span style="color:#666666;">根据实验主要功能</span><span style="color:#666666;">—</span><span style="color:#666666;">插入,定义了插入函数</span></p><p align="left"><span style="color:#666666;">void rbInsert(RBT* *root, RBT* pZ); </span></p><p align="left"><span style="color:#666666;">而插入函数需要调整红黑树结构,定义红黑树调整函数:</span></p><p align="left"><span style="color:#666666;">void rbFixUp(RBT **root, RBT *pZ);//</span><span style="color:#666666;">插入后的调整</span></p><p align="left"><span style="color:#666666;">在调整函数中又需要调用左旋操作和右旋操作:</span></p><p align="left"><span style="color:#666666;">void leftRotate(RBT* *root, RBT *pX); //</span><span style="color:#666666;">左旋操作</span></p><p align="left"><span style="color:#666666;">void rightRotate(RBT** root, RBT *pX); //</span><span style="color:#666666;">右旋操作</span></p><p align="left"><span style="color:#666666;">为了显示红黑树而定义了先序遍历的红黑树打印函数:</span></p><p align="left"><span style="color:#666666;">void treePrint(RBT **root); //</span><span style="color:#666666;">打印一棵树</span><span style="color:#666666;">,</span><span style="color:#666666;">先序遍历</span></p><p align="left"><span style="color:#666666;">打印红黑树的过程中需要调用对每一个结点的打印函数:</span></p><p align="left"><span style="color:#666666;">void rbPrint(RBT* pX); //</span><span style="color:#666666;">打印一个结点</span></p><p align="left"><span style="color:#333333;"></span><span style="color:#333333;">代码如下:</span><span style="color:#333333;"></span><span style="color:#333333;"></span><pre name="code" class="cpp">#include <iostream>
#include <stdio.h>
#include <time.h>
using namespace std;

#define red 0
#define black 1
#define SIZE 10 //待插入的元素个数
#define MAX 100 //待插入元素的范围0~MAX
typedef struct RB
{
int key; //关键字
int color; //颜色
struct RB *ptParent; //指向父结点的指针
struct RB *ptLeft; //指向左孩子的指针
struct RB *ptRight; //指向右防子的指针
}RBT; //定义结构体RBT来表示红黑树一个结点

void leftRotate(RBT* *root, RBT *pX); //左旋操作
void rbFixUp(RBT **root, RBT *pZ);//插入后的调整
void rightRotate(RBT** root, RBT *pX); //右旋操作
void rbInsert(RBT* *root, RBT* pZ); //插入操作
void rbPrint(RBT* pX); //打印一个结点
void treePrint(RBT **root); //打印一棵树,先序遍历
void Random(int *A, int max, int length);//产生一个长度为length数组,
//数组元素随机分布在0~max间,且不重复,
//时间复杂度为O(max)

int main()
{

RBT **root; //root指向根结点
root = (RBT**)malloc(sizeof(RBT*));
*root = NULL;//初始时树为空

int *A; //A用来存放待入元素
A = (int*)malloc(sizeof(int)*SIZE);
int i;
/*    for(i=0; i<SIZE; i++)
{
A[i] = rand()%100;
printf("%d ", A[i]);
}*/
Random(A, MAX, SIZE);
for(i=0; i<SIZE; i++)
{
printf("%d ", A[i]);
}
puts("\n");
for(i=0; i<SIZE; i++)
{
RBT *pZ = (RBT*)malloc(sizeof(RBT));//定义一个指向新结点的指针pZ
printf("\nNow insert the element %d:\n", A[i]);
pZ->key = A[i];
rbInsert(root, pZ);
treePrint(root);//打印当前红黑树结构
system("pause");
}
puts("\nThe total tree is:\n ");

treePrint(root);
system("pause");
return 0;
}

//以下的各函数的定义

//左旋
void leftRotate(RBT* *root, RBT* pX)
{
RBT* pY;
pY = pX->ptRight;

if(pX->ptRight != NULL && pY != NULL)
pX->ptRight = pY->ptLeft;
if(pY != NULL && pY->ptLeft != NULL)
pY->ptLeft->ptParent = pX; //将Y的左孩子变成X的右孩子
if(pY != NULL)
pY->ptParent = pX->ptParent;
if(pX->ptParent == NULL)
*root = pY; //如果pX结点是根那么让pY成为新的根
else
{
if(pX == pX->ptParent->ptLeft)
pX->ptParent->ptLeft = pY;
else
pX->ptParent->ptRight = pY;
}
if(pY!=NULL)
pY->ptLeft = pX;
pX->ptParent = pY;
}

//右旋
void rightRotate(RBT** root, RBT *pX)
{
RBT* pY;
pY = pX->ptLeft;

if(pX->ptLeft != NULL && pY != NULL)
pX->ptLeft = pY->ptRight;
if(pY->ptRight != NULL && pY->ptLeft != NULL)
pY->ptRight->ptParent = pX; //将Y的右孩子变成X的左孩子

pY->ptParent = pX->ptParent;
if(pX->ptParent == NULL)
*root = pY; //如果pX结点是根那么让pY成为新的根
else
{
if(pX == pX->ptParent->ptLeft)
pX->ptParent->ptLeft = pY;
else
pX->ptParent->ptRight = pY;
}

pY->ptRight = pX;
pX->ptParent = pY;
}

//红黑树插入
void rbInsert(RBT* *root, RBT* pZ)
{
RBT *pY, *pX;
pY = NULL;
pX = *root;

while(pX != NULL)
{
pY = pX;
if(pZ->key < pX->key)
pX = pX->ptLeft;
else
pX = pX->ptRight;
}

pZ->ptParent = pY;

if(pY == NULL)
*root = pZ;
else
{
if(pZ->key < pY->key)
pY->ptLeft = pZ;
else
pY->ptRight = pZ;
}

pZ->ptLeft = pZ->ptRight = NULL;

pZ->color = red;

rbFixUp(root,pZ);

}

//红黑树调整
void rbFixUp(RBT **root, RBT *pZ)
{
if(*root != NULL)
{
RBT *pY;
while(pZ->ptParent != NULL && pZ->ptParent->color == red)
{
if(pZ->ptParent->ptParent->ptLeft == pZ->ptParent)
{
pY = pZ->ptParent->ptParent->ptRight; //Y是Z的叔叔

if(pY!=NULL && pY->color == red)//第一种情况
{
pZ->ptParent->color = pY->color = black;
pZ->ptParent->ptParent->color = red;
pZ = pZ->ptParent->ptParent; //上溯到Z的爷爷,再进行调整
}

else //第二 三种情况
{
if(pZ == pZ->ptParent->ptRight) //case2->case3
{
pZ = pZ->ptParent;
leftRotate(root, pZ);
}
pZ->ptParent->color = black;
pZ->ptParent->ptParent->color = red;
rightRotate(root, pZ->ptParent->ptParent);
}
}
else
{
pY = pZ->ptParent->ptParent->ptLeft;

if(pY != NULL && pY->color == red)
{
pZ->ptParent->color = pY->color = black;
pZ->ptParent->ptParent->color = red;
pZ = pZ->ptParent->ptParent;
}
else
{
if(pZ == pZ->ptParent->ptLeft)
{
pZ = pZ->ptParent;
rightRotate(root, pZ);
}
pZ->ptParent->color = black;
pZ->ptParent->ptParent->color = red;
leftRotate(root,pZ->ptParent->ptParent);
}
}
}
(*root)->color = black;
}
}

//打印结点
void rbPrint(RBT* pX)
{
if(pX !=NULL)
{
printf("key: %d\t", pX->key);

if(pX->color == red)
printf("color: red\t");
else
printf("color: black\t");

if(pX->ptLeft != NULL)
printf("left: %d \t", pX->ptLeft->key);
else
printf("left: nil\t");

if(pX->ptRight != NULL)
printf("right: %d\t", pX->ptRight->key);
else
printf("right: nil\t");

if(pX->ptParent != NULL)
printf("parent: %d\t", pX->ptParent->key);
else
printf("*root\t");
}
else
printf("empty");
puts("\n");
}

//从根结点开始先序遍历,打印树
void treePrint(RBT** root)
{
if(*root != NULL)
{
rbPrint(*root);
treePrint(&((*root)->ptLeft));
treePrint(&((*root)->ptRight));
}
}

//产生一个长度为length,元素随机分布在0~max之间的数组A

void Random(int *A, int max, int length)
{
srand(time(NULL));
int i;
int c;
int k = max+1;
int *B = (int*)malloc(sizeof(int)*k);
for(i=0; i<k; i++)
B[i] = i;
for(i=0; i<length; i++)
{
c = rand()%k;
k--;
A[i] = B[c];
B[c] = B[k];
}
}


程序编译通过,正常运行.
随机产生的待插入元素为:
54 62 81 91 34 9 16 74 48 24
最后输出结果为:
The total tree is:
key: 62 color: black   left: 34        right:81       *root
key: 34 color:red      left:16        right:54       parent: 62
key: 16 color: black   left: 9         right:24       parent: 34
key: 9 color:red      left: nil      right: nil      parent: 16
key: 24 color:red      left: nil      right: nil      parent: 16
key: 54 color: black   left: 48        right:nil      parent: 34
key: 48 color:red      left: nil      right: nil      parent: 54
key: 81 color: black   left: 74       right:91       parent: 62
key: 74 color:red      left: nil      right: nil      parent: 81
key: 91 color:red      left: nil      right: nil      parent: 81
最终输出满足红黑树性质。
且中间每一步输出正确。
主函数int main()
{ …
return 0;
}
The thread 0x924 has exited with code 0(0x0).
The program 'D:\PhanYoung\课堂\Algorithm\实验\实验二红黑树的插入\Debug\rbt.exe'has
exited with code 0 (0x0).
函数正常结束.获得正确结果.
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息