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

题目详情: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[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");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值