您的位置:首页 > 其它

1135. Is It A Red-Black Tree (30)

2017-10-06 20:17 246 查看
题目详情:https://www.patest.cn/contests/pat-a-practise/1135

刚看到这道题的感觉很难,现在做出来了,感觉也就那么回事啊[傲娇脸]!

红黑树满足以下5条性质:

1、节点是红色或者黑色

2、根节点为黑色

3、每个叶节点(NIL节点,空节点)是黑色的

4、每个红色节点的子节点都是黑色的,即不能有两个连续的红色节点

5、从任一节点到其每个叶子的所有路径都包含相同数量的黑色节点

本题中,性质1、3是不用检查,需要检查的性质只有2、4、5。

首先明确,红黑树是一棵平衡二叉树,平衡二叉树是一棵二叉搜索树。那么红黑树满足平衡二叉树和二叉搜索树的性质。我是根据二叉搜索树的性质来还原这棵树的。

性质2只需要判断根节点的政府即可。

性质4用前序遍历检查

性质5用后续遍历来检查

#include <iostream>
#include <vector>
#include <malloc.h>
#include <math.h>
#include <string.h>
using namespace std;
#define N 33
typedef struct BTree
{
struct BTree* leftBTree;
int value;
struct BTree* rightBTree;
}BTree;
BTree* buildBTree(int* pre,int start,int end)//start和end用来限制访问的范围
{//根据二叉搜索树的性质和红黑树前序遍历序列来还原红黑树
if (start==end)//起始位置和结束位置相同,那么代表空节点
return NULL;
int i;
for(i=start;i<end;i++)//找到比pre[start]的第一个位置后停止
{//根据二叉搜索树的性质,该位置右侧的数在右子树上
if( abs(pre[i])>abs(pre[start]) )
break;
}
BTree* root=(BTree*)malloc(sizeof(BTree));//建立"根节点"
root->value=pre[start];
root->leftBTree=buildBTree(pre,start+1,i);//递归建立左子树
root->rightBTree=buildBTree(pre,i,end);//递归建立右子树
return root;
}
int postOrder(BTree* root)//后续遍历检查路径上是否由相同的黑色节点数量
{
if(root!=NULL)
{
int leftBlack=postOrder(root->leftBTree);//leftBlack存左子树的黑色节点数量
int rightBlack=postOrder(root->rightBTree);//rightBlack存右子树的黑色节点数量
if ( leftBlack<0 || rightBlack<0 || rightBlack!=leftBlack )
return -1; //黑色节点数不相等,或左子树、右子树已经存在不等的黑色节点数则返回一个负数
else if(root->value<0)//本节点为红色,则不加上本节点
return leftBlack;
else//本节点为黑色
return leftBlack+1;//加上本黑色节点
}
return 0;
}
int previousOrder(BTree* root) //前序遍历用以检查是否有连续的两个红色节点
{
if(root)
{
if(root->value<0)//本届点为红色节点
{
if(root->leftBTree)//左子树非空
{
if(root->leftBTree->value<0)//左节点为红色
return 1;//则返回真值(1),代表有连续的红色节点
}
if(root->rightBTree)//右子树非空
{
if(root->rightBTree->value<0)//右节点为红色
return 1;//则返回真值(1),代表有连续的红色节点
}
}
return previousOrder(root->leftBTree) || previousOrder(root->rightBTree);//递归进行检查
}
return 0;//空节点则返回假值,代表没有连续的两个红色节点
}
int main()
{
int k,n,preOrder
;
scanf("%d",&k);//输入循环的次数
for(int i=0;i<k;i++)
{
scanf("%d",&n);//输入节点的个数,n为一个正数
memset(preOrder,0,n);//将preOrder数组的前n个元素全部置为0
for(int j=0;j<n;j++)
scanf("%d",&preOrder[j]);//存储前序遍历的序列
if(preOrder[0]<0)//负号代表红色节点,根节点为红色,则不符合要求
{//保证根节点是黑色的
printf("No\n");
continue;
}
BTree* root=buildBTree(preOrder,0,n);//还原(构建)红黑树
//用后续遍历来判断是否连续的两个节点为红色,路径上的黑色节点数量是否相同
//balance用来存储路径的黑色节点是否相同,非负数相同,负数(-1)代表数量不相同
//continous用来存储两个红色的节点是否连续,1代表连续,
int balance=postOrder(root);
int continous=previousOrder(root);
//如果路径上黑色节点数量不同或者存在连续的红色节点
if( balance<0 || continous==1)
printf("No\n");
else
printf("Yes\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: