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

来源:互联网 发布:mysql导出数据库 编辑:程序博客网 时间:2024/06/04 20:14

题目详情: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 33typedef 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[N];    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");    }}