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

16 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
第一次尝试:没留意红黑树是BST,直接用回溯+非递归建树列举了所有可能情况:

#include<cstdio>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> preorder;
struct node {
	int val, depth;
	node *left, *right;
	node(int v) {
		val = v;
		left = NULL;
		right = NULL;
		depth = 1;
	}
};
node *dummy;
int weight = -1;
bool checkWeight(node *root, int curWeight) {
	if (root == NULL) {
		curWeight++;
		if (weight == -1) {
			weight = curWeight;
			return true;
		}
		else return curWeight == weight;
	}
	if (root->val > 0) {
		curWeight++;
	}
	if (checkWeight(root->left, curWeight) == false) {
		return false;
	}
	return checkWeight(root->right, curWeight);
}

bool buildTree(node *cur, int index, stack<node*> st) {
	if (cur == dummy->right) {
		return false;
	}
	if (index == preorder.size()) {
		weight = -1;
		bool b = checkWeight(dummy->left, 0);
		return b;
	}
	if (preorder[index] > 0) {	//下一结点为黑结点
		cur->left = new node(preorder[index]);
		st.push(cur->left);
		if (buildTree(cur->left, index + 1, st))
			return true;
		st.pop();
		cur->left = NULL;
	}
	else {	//下一结点为红结点
		if (cur->val > 0) {	//当前是黑结点
			cur->left = new node(preorder[index]);
			st.push(cur->left);
			if (buildTree(cur->left, index + 1, st))
				return true;
			st.pop();
			cur->left = NULL;
		}
	}
	while (!st.empty()) {
		cur = st.top();
		st.pop();
		if (preorder[index] > 0) {	//下一结点为黑结点
			cur->right = new node(preorder[index]);
			st.push(cur->right);
			if (buildTree(cur->right, index + 1, st))
				return true;
			st.pop();
			cur->right = NULL;
		}
		else {	//下一结点为红结点
			if (cur->val > 0) {
				cur->right = new node(preorder[index]);
				st.push(cur->right);
				if (buildTree(cur->right, index + 1, st))
					return true;
				st.pop();
				cur->right = NULL;
			}
		}
	}
	return false;
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0;i < n;i++) {
		int size;
		scanf("%d", &size);
		preorder.resize(size);
		for (int j = 0;j < size;j++) {
			scanf("%d", &preorder[j]);
		}
		dummy = new node(-1);
		stack<node*> temp;
		bool isRBT = buildTree(dummy, 0, temp);
		if (isRBT) {
			printf("Yes\n");
		}
		else printf("No\n");
	}
}

第二次尝试:尝试借助栈根据BST有序这一特性和先序序列非递归建树:

struct node {
	int val;
	node *left, *right, *parent;
	node(int v) {
		val = v;
		left = NULL;
		right = NULL;
		parent = NULL;
	}
};
		//建树
		int index = 0;
		stack<node*> st;
		node *root = new node(preorder[index++]), *cur = root;
		st.push(root);
		while (index < preorder.size()) {
			while (index < preorder.size() && abs(preorder[index]) < abs(cur->val)) {
				cur->left = new node(preorder[index++]);
				cur->left->parent = cur;
				cur = cur->left;
				st.push(cur);
			}
			if (index < preorder.size()) {
				while (!st.empty() && cur->parent != NULL && cur->parent->left == cur && abs(cur->parent->val) < abs(preorder[index])) {	//不能插入正确位置,应该改写插入条件
					cur = st.top();
					st.pop();
				}
				cur->right = new node(preorder[index++]);
				cur->right->parent = cur;
				cur = cur->right;
				st.push(cur);
			}
		}

以上方法并不能正确地建树,当结点要插入右子树时并不能插入到正确位置。
改正后的建树方法及完整代码:

#include<cstdio>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
struct node {
	int val;
	node *left, *right, *parent;
	node(int v) {
		val = v;
		left = NULL;
		right = NULL;
		parent = NULL;
	}
};
vector<int> preorder;
bool checkRedNode(node *cur) {	//条件(4),满足则返回true
	if (cur == NULL)
		return true;
	if (cur->val < 0) {	//当前结点为红结点
		if (cur->left != NULL && cur->left->val < 0 || cur->right != NULL && cur->right->val < 0) {
			return false;
		}
	}
	if (checkRedNode(cur->left) == false) {
		return false;
	}
	return checkRedNode(cur->right);
}
int blackCount = -1;
bool checkBlack(node *cur, int count) {	//条件(5),满足则返回true
	if (cur == NULL) {
		count++;
		if (blackCount == -1) {
			blackCount = count;
			return true;
		}
		else return blackCount == count;
	}
	if (cur->val > 0)	//黑结点
		count++;
	return checkBlack(cur->left, count) && checkBlack(cur->right, count);
}
bool traverse(node *cur) {	//遍历判定每个结点
	if (cur == NULL)
		return true;
	blackCount = -1;
	if (checkBlack(cur, 0) == false)
		return false;
	return traverse(cur->left) && traverse(cur->right);
}

bool isInsertPos(node *pos, int val) {
	while (pos->parent != NULL) {
		if (pos->parent->left == pos) {	//该结点是左子树
			if (abs(pos->parent->val) < abs(val))
				return false;
		}
		else {
			if (abs(pos->parent->val) > abs(val))
				return false;
		}
		pos = pos->parent;
	}
	return true;
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0;i < n;i++) {
		int size;
		scanf("%d", &size);
		preorder.resize(size);
		for (int j = 0;j < size;j++) {
			scanf("%d", &preorder[j]);
		}

		//建树
		int index = 0;
		stack<node*> st;
		node *root = new node(preorder[index++]), *cur = root;
		st.push(root);
		while (index < preorder.size()) {
			while (index < preorder.size() && abs(preorder[index]) < abs(cur->val)) {
				cur->left = new node(preorder[index++]);
				cur->left->parent = cur;
				cur = cur->left;
				st.push(cur);
			}
			if (index < preorder.size()) {
				while (!isInsertPos(cur, preorder[index])) {
					cur = st.top();
					st.pop();
				}
				cur->right = new node(preorder[index++]);
				cur->right->parent = cur;
				cur = cur->right;
				st.push(cur);
			}
		}

		bool isRBTree = true;
		if (root->val < 0 || !checkRedNode(root) || !traverse(root)) {
			isRBTree = false;
		}
		if (isRBTree) {
			printf("Yes\n");
		}
		else printf("No\n");
	}
}

改进:
给出BST的先序序列,可以直接根据先序序列依次将结点插入树中,就能直接得到所求二叉树。

注意:

  • 红黑树的结点两子树的高度差可以大于2,所以不用判断树的平衡性。
  • 要判断每个结点到叶节点遍历的黑结点数。
  • 判断红结点是否有子结点是红结点。

AC代码:

#include<cstdio>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
struct node {
	int val;
	node *left, *right;
	node(int v) {
		val = v;
		left = NULL;
		right = NULL;
	}
};
vector<int> preorder;
bool checkRedNode(node *cur) {	//条件(4),满足则返回true
	if (cur == NULL)
		return true;
	if (cur->val < 0) {	//当前结点为红结点
		if (cur->left != NULL && cur->left->val < 0 || cur->right != NULL && cur->right->val < 0) {
			return false;
		}
	}
	if (checkRedNode(cur->left) == false) {
		return false;
	}
	return checkRedNode(cur->right);
}
int blackCount = -1;
bool checkBlack(node *cur, int count) {	//条件(5),满足则返回true
	if (cur == NULL) {
		count++;
		if (blackCount == -1) {
			blackCount = count;
			return true;
		}
		else return blackCount == count;
	}
	if (cur->val > 0)	//黑结点
		count++;
	return checkBlack(cur->left, count) && checkBlack(cur->right, count);
}
bool traverse(node *cur) {
	if (cur == NULL)
		return true;
	blackCount = -1;
	if (checkBlack(cur, 0) == false)
		return false;
	return traverse(cur->left) && traverse(cur->right);
}
void insert(node *&cur, int val) {
	if (cur == NULL) {
		cur = new node(val);
		return;
	}
	if (abs(val) < abs(cur->val)) {
		insert(cur->left, val);
	}
	else insert(cur->right, val);
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0;i < n;i++) {
		int size;
		scanf("%d", &size);
		preorder.resize(size);
		for (int j = 0;j < size;j++) {
			scanf("%d", &preorder[j]);
		}

		//建树
		node *root = NULL;
		for (int i = 0;i < preorder.size();i++) {
			insert(root, preorder[i]);
		}

		bool isRBTree = true;
		if (root->val < 0 || !checkRedNode(root) || !traverse(root)) {
			isRBTree = false;
		}
		if (isRBTree) {
			printf("Yes\n");
		}
		else printf("No\n");
	}
}

二刷:
每个结点到叶结点的黑结点数都要相同,仅仅数一下从根到叶结点的黑结点数是不行的。

#include<iostream>
#include<string>
#include<unordered_set>
#include<cmath>
#include<algorithm>
using namespace std;
struct node {
	int val;
	node *left, *right;
	node(int v) {
		val = v;
		left = NULL;
		right = NULL;
	}
}*root = NULL;
bool isRedBlackTree = true;
//将结点插入BST中
void insert(node *&cur, int val) {
	if (cur == NULL) {
		cur = new node(val);
		return;
	}
	if (abs(cur->val) > abs(val)) {
		insert(cur->left, val);
	}
	else insert(cur->right, val);
}
int blackCount;
//数从当前结点到叶结点的路径的黑结点数
void countBlack(node *cur, int count) {
	if (cur == NULL) {
		if (blackCount == -1) {
			blackCount = count;
		}
		else if (count != blackCount) {
			isRedBlackTree = false;
		}
		return;
	}
	if (cur->val > 0) {
		count++;
	}
	countBlack(cur->left, count);
	if (isRedBlackTree == false) {
		return;
	}
	countBlack(cur->right, count);
}
void preorderTraverse(node *cur) {
	blackCount = -1;
	countBlack(cur, 0);
	if (isRedBlackTree == false) {
		return;
	}
	if (cur->left != NULL) {
		if (cur->val < 0 && cur->left->val < 0) {
			isRedBlackTree = false;
			return;
		}
		preorderTraverse(cur->left);
	}
	if (cur->right != NULL) {
		if (cur->val < 0 && cur->right->val < 0) {
			isRedBlackTree = false;
			return;
		}
		preorderTraverse(cur->right);
	}
}
int main() {
	int numCase;
	cin >> numCase;
	for (int i = 0; i < numCase; i++) {
		root = NULL;
		isRedBlackTree = true;
		int numNode;
		cin >> numNode;
		for (int j = 0; j < numNode; j++) {
			int val;
			cin >> val;
			insert(root, val);
		}
		if (root->val < 0) {
			isRedBlackTree = false;
		}
		preorderTraverse(root);
		if (isRedBlackTree) {
			cout << "Yes" << endl;
		}
		else cout << "No" << endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值