PAT.1135 Is It A Red-Black Tree

PAT.1135 Is It A Red-Black Tree

题目链接

哈哈,红黑树。

第一眼看过去被吓到了,还以为要把红黑树的几个基本操作都写出来。定睛一看发现还是一道建树的题,只不过建完树要根据红黑树的定义判断一下当前树是不是红黑树。

这道题可以建树的基本前提是,红黑树是一种特殊的二叉搜索树,所以仍然保有中序有序的性质,因此给定前序遍历的同时可以通过排序得到中序遍历。

递归建树的过程自然不必多说,这道题唯一的特点无非就是红黑树的判断。

根节点必须为黑、所有节点非红即黑、所有Null节点为黑这三点的难度约等于没有。

而所有红色节点的孩子必须为黑色节点,这个条件只要随便在什么遍历顺序里对红色节点的孩子进行判断即可。

至于任意节点到其后继叶子结点的所有路径黑色深度相等这个条件,可以发现,只要一个节点的左右子树的根节点满足这个条件,那么当前根节点也一定满足,因此类似建树策略递归判断即可。

题解

一开始读题的时候读错了,以为节点的值会落在[1,N]范围内,所以用了一个redFlag数组来记录值对应节点的颜色,后来提交碰到段错误才发现这个问题。

仅针对这题而言,只要regFlag数组开的足够大这样用也是可以的,不过出于鲁棒性之类的考虑还是应该用map之类的结构记录。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct node{
    int val;
    bool isRed;
    node *left,*right;
    node();
    node(int t,bool flag){
        this->isRed = flag;
        this->val = t;
        this->left = this->right = nullptr;
    }
};

int caseCnt,nodeCnt,preOrder[35],inOrder[35],redFlag[10005];
node *root;

//前序左界,前序右界,中序左界,中序右界
node *build(int pl,int pr,int il,int ir){
    int cRootVal = preOrder[pl],cRootInOrderIndex = il;
    node *cNode = new node(cRootVal,(redFlag[cRootVal] == 1));
    if(pl > pr || il > ir) return nullptr;
    else if(pl == pr || il == ir) return cNode;
    while(inOrder[cRootInOrderIndex] != cRootVal) cRootInOrderIndex++;
    //左子树元素个数
    int cLeftChildSize = cRootInOrderIndex - il;
    cNode->left = build(pl+1,pl+cLeftChildSize,il,cRootInOrderIndex-1);
    cNode->right = build(pl+cLeftChildSize+1,pr,cRootInOrderIndex+1,ir);
    return cNode;
}

//检查红色节点的孩子是否都为黑色节点
bool checkRedChildren(node *cNode){
    bool res = true;
    if(cNode->isRed) res = (cNode->left == nullptr || !(cNode->left->isRed)) && (cNode->right == nullptr || !(cNode->right->isRed));
    if(cNode->left != nullptr) res = res && checkRedChildren(cNode->left);
    if(cNode->right != nullptr) res = res && checkRedChildren(cNode->right);
    return res;
}

//检查黑色深度
int checkBlackDepth(node *cNode){
    int leftBlackDepth = 1,rightBlackDepth = 1;
    if(cNode->left != nullptr) leftBlackDepth = checkBlackDepth(cNode->left);
    if(cNode->right != nullptr) rightBlackDepth = checkBlackDepth(cNode->right);
    if(leftBlackDepth != rightBlackDepth || (leftBlackDepth == -1 && rightBlackDepth == -1)) return -1;
    else return (cNode->isRed ? 0 : 1) + leftBlackDepth;
}

//根黑,null黑,非红即黑,红子均黑,任意节点到后裔叶子结点的黑色高度相同
int main(){
    cin>>caseCnt;
    while(caseCnt--){
        cin>>nodeCnt;
        memset(redFlag,0,sizeof(redFlag));
        for(int i = 0 ; i < nodeCnt ; ++i){
            cin>>preOrder[i];
            inOrder[i] = abs(preOrder[i]);
            if(preOrder[i] < 0) redFlag[inOrder[i]] = 1;
            preOrder[i] = abs(preOrder[i]);
        }
        sort(inOrder,inOrder + nodeCnt);
        root = build(0,nodeCnt - 1,0,nodeCnt - 1);
        if(root->isRed) cout<<"No"<<endl;
        else if(!checkRedChildren(root)) cout<<"No"<<endl;
        else if(checkBlackDepth(root) == -1) cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值