# PAT甲级1135----红黑树题解

## 题目描述

1. Is It A Red-Black Tree (30)
时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

There is a kind of balanced binary search tree named red-black tree in the data structure. It has the following 5 properties:

(1) Every node is either red or black.
(2) The root is black.
(3) Every leaf (NULL) is black.
(4) If a node is red, then both its children are black.
(5) For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.

For example, the tree in Figure 1 is a red-black tree, while the ones in Figure 2 and 3 are not.

Figure 1

Figure 2

Figure 3

For each given binary search tree, you are supposed to tell if it is a legal red-black tree.

Input Specification:

Each input file contains several test cases. The first line gives a positive integer K (<=30) which is the total number of cases. For each case, the first line gives a positive integer N (<=30), the total number of nodes in the binary tree. The second line gives the preorder traversal sequence of the tree. While all the keys in a tree are positive integers, we use negative signs to represent red nodes. All the numbers in a line are separated by a space. The sample input cases correspond to the trees shown in Figure 1, 2 and 3.

Output Specification:

For each test case, print in a line “Yes” if the given tree is a red-black tree, or “No” if not.
Sample Input:

3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17

Sample Output:

Yes
No
No

## 题目理解

1、根节点是否为正数
2、节点为负数的节点的孩子是否为正数
3、从根节点到叶子节点所有路径拥有相同的黑色节点

## 建离二叉链树

/*
**per[perL~preR]之间代表的是二叉子树前序遍历，初始值因为整棵树
*/
Tree* buildTree(int preL,int preR){
//如果左索引比右索引说明递归到的是叶子节点的子节点，自然为NULL
if(preL>preR)
return NULL;
Tree *tree = new Tree(pre[preL]);
//在前序数组中，找到第一个比根节点大的节点即为右子树的根节点
int i = preL+1;
for(;i<=preR;++i){
if(abs(pre[i])>abs(pre[preL])){
break;
}
}
//递归建立左右子树
tree->left = buildTree(preL+1,i-1);
tree->right = buildTree(i,preR);
//返回根节点
return tree;
}


## 红黑树判断

/*
**@tree 根节点
**@isRedroot 根节点是否为红色如果是红色就要判断当前节点是不是黑了
**@num_blacknodes 记录当前路径已经遍历的黑色节点个数
**
**@flag 初始值为true，他只有改为false的机会，只要我们某一次判断是错的他的值变永久性改为false
**@first 状态位，是不是第一次到达叶子节点
**@num 记录第一次到达叶子节点时经过的黑色节点个数，并作为判断从根节点出发到叶子节点的其他路径是否与第一次相等的凭借
*/
void judge(Tree *tree,bool isRedroot,int num_blacknodes){
//如果当前节点为空，代表父节点为叶子节点
if(tree==NULL){
//如果第一次抵达叶子节点，那么用num存储，黑色节点的个数
if(first){
num = num_blacknodes;
first = false;
}else{
//如果不是第一次，就进行红黑树的第五条性质判断
if(num!=num_blacknodes){
flag = false;
}
}
}else{
//记录当前节点颜色
bool isBlack = tree->data>0;
//如果父节点是红色，而当前节点也是红色，那么就不是红黑树
if(isRedroot&&!isBlack){
flag = false;
}
judge(tree->left,!isBlack,num_blacknodes+isBlack);
judge(tree->right,!isBlack,num_blacknodes+isBlack);
}
}

## 完整代码

#include <iostream>
#include <cmath>

using namespace std;

struct Tree{
int data;
Tree *left;
Tree *right;
Tree(int d):data(d){}
};

int pre[30];

Tree* buildTree(int preL,int preR){
if(preL>preR)
return NULL;
Tree *tree = new Tree(pre[preL]);
int i = preL+1;
for(;i<=preR;++i){
if(abs(pre[i])>abs(pre[preL])){
break;
}
}
tree->left = buildTree(preL+1,i-1);
tree->right = buildTree(i,preR);
return tree;
}

void freeMemory(Tree *tree){
if(tree!=NULL){
freeMemory(tree->left);
freeMemory(tree->right);
delete tree;
tree = NULL;
}
}

bool flag,first;
int num;

void judge(Tree *tree,bool isRedroot,int num_blacknodes){
if(tree==NULL){
if(first){
num = num_blacknodes;
first = false;
}else{
if(num!=num_blacknodes){
flag = false;
}
}
}else{
bool isBlack = tree->data>0;
if(isRedroot&&!isBlack){
flag = false;
}
judge(tree->left,!isBlack,num_blacknodes+isBlack);
judge(tree->right,!isBlack,num_blacknodes+isBlack);
}
}

int main(int argc, char const *argv[])
{
int K;
cin >> K;
for (int i = 0; i < K; ++i)
{
int N;
cin >> N;
flag = first = true;
num = 0;
for (int j = 0; j < N; ++j)
{
cin >> pre[j];
}
Tree *tree = buildTree(0,N-1);
if(tree->data<0){
flag = false;
}else{
judge(tree,false,0);
}
cout << (flag?"Yes":"No") << endl;
freeMemory(tree);
}
return 0;
}