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

这是一个关于红黑树的问题,需要判断给定的二叉搜索树是否符合红黑树的性质。红黑树有5个特性,包括节点颜色、根节点颜色、叶子节点颜色、红色节点子节点颜色以及路径上黑色节点数量的约束。对于每个测试用例,根据前序遍历序列判断树是否合法,并输出结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1135. 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.每个空节点为黑(这个理解了半天,看图一叶子结点有红也有黑啊,它这里意思应该是叶子结点在下去的空节点算作黑,这样就满足条件4,叶子红结点也有2个黑结点孩子)

4.红结点孩子为黑

5.每一个结点到其叶子结点的黑结点数相同。


写函数只要判断条件2 4 5

方法一:

根据前序,中序建树,为什么测试点1段错误呢?

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef struct Node *node;
int flag,flag2;
struct Node{
	int x;
	int fu;//0:+  1:-
	node left;
	node right;
}pre[35],in[35];

bool cmp(Node a,Node b){
	return a.x<b.x;
}
node build(int s1,int e1,int s2,int e2){//根据前序 中序建树 
	node T=(node)malloc(sizeof(struct Node));
	T->fu=pre[s1].fu;
	T->x=pre[s1].x;
	T->left=T->right=0;
	int root,i;
	for(i=s2;i<=e2;i++){
		if(in[i].x==pre[s1].x){
			root=i;break;
		}
	}
	if(root!=s2){
		T->left=build(s1+1,s1+root-s2,s2,root-1);
	}
	if(root!=e2){
		T->right=build(s1+root-s2+1,e1,root+1,e2);
	}
	return T;
}

void dfs(node T){
	if(T){
		if(T->fu){
			if(T->left&&T->left->fu){//红结点有左孩子并且也为红
				flag=1;return;
			}
			if(T->right&&T->right->fu){//红结点有右孩子并且也为红
				flag=1;return;
			}
		}
		dfs(T->left);
		dfs(T->right);
	}
}

int getblack(node T){
	if(T){
		int left=getblack(T->left);
		int right=getblack(T->right);
		if(left!=right){//左右黑结点数不相等 
			flag2=1;
		}
		int maxn=max(left,right);
		if(T->fu==0){//若该节点为黑
			maxn++;
		}
		return maxn;
	}
	else{
		return 0;
	}
}

int judge(node T){
	if(T->fu){//条件2
		return 0;
	}
	dfs(T);//条件4 
	if(flag){
		return 0;
	}
	getblack(T);//条件5 
	if(flag2){
		return 0;
	}
	return 1;
}

int main(){
	int k,n,i,tmp;
	scanf("%d",&k);
	while(k--){
		scanf("%d",&n);
		for(i=0;i<n;i++){
			scanf("%d",&tmp);
			pre[i].x=abs(tmp);
			if(tmp<0){
				pre[i].fu=1;
			}
			else{
				pre[i].fu=0;
			}
			in[i]=pre[i];
		}
		sort(in,in+n,cmp);//二叉搜索树中序必升序 
		node T=0;
		T=build(0,n-1,0,n-1);//根据前序 中序建树 
		flag=flag2=0;
		if(judge(T)){
			printf("Yes\n");
		}
		else{
			printf("No\n");
		}
	} 
} 

方法二:

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef struct Node *node;
int flag,flag2;
struct Node{
	int x;
	int fu;//0+  1-
	node left;
	node right;
}pre[35],in[35];

void dfs(node T){ 
	if(T){
		if(T->fu){//红结点 
			if(T->left&&T->left->fu){//红结点有左孩子并且也为红 
				flag=1;return;
			}
			if(T->right&&T->right->fu){//红结点有右孩子并且也为红
				flag=1;return;
			}
		}
		dfs(T->left);
		dfs(T->right);
	}
}

int getblack(node T){
	if(T){
		int left=getblack(T->left);
		int right=getblack(T->right);
		if(left!=right){//左右黑结点数不相等 
			flag2=1;
		}
		int maxn=max(left,right);
		if(T->fu==0){//若该节点为黑 
			maxn++;
		}
		return maxn;
	}
	else{
		return 0;
	}
}

int judge(node T){
	if(T->fu){//条件2
		return 0;
	}
	dfs(T);//条件4 
	if(flag){
		return 0;
	}
	getblack(T);//条件5 
	if(flag2){
		return 0;
	}
	return 1;
}

node insert(node T,Node a){//根据前序又是二叉搜索树  建树
	if(!T){
		T=(node)malloc(sizeof(struct Node));
		T->fu=a.fu;
		T->x=a.x;
		T->left=T->right=0;
	}
	else if(a.x<T->x){
		T->left=insert(T->left,a);
	}
	else{
		T->right=insert(T->right,a);
	}
	return T;
}
int main(){
	int k,n,i,tmp;
	scanf("%d",&k);
	while(k--){
		scanf("%d",&n);
		node T=0;
		for(i=0;i<n;i++){
			scanf("%d",&tmp);
			pre[i].x=abs(tmp);
			if(tmp<0){
				pre[i].fu=1;
			}
			else{
				pre[i].fu=0;
			}
			T=insert(T,pre[i]);//根据前序又是二叉搜索树  建树 
		}
		flag=flag2=0;
		if(judge(T)){
			printf("Yes\n");
		}
		else{
			printf("No\n");
		}
	} 
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值