1135 Is It A Red-Black Tree(判断是否是红黑树)

题目:https://pintia.cn/problem-sets/994805342720868352/problems/994805346063728640

红黑树满足二叉查找树的性质,左小于根,根小于右。

红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的(从每个叶子到根的所有路径上不能有两个连续的红色节点) 。
(5)从任一节点到其每个叶子节点(NULL)的所有简单路径都包含相同数目的黑色节点。

方法一:建立二叉树后,依次判断各个性质的合法性

如何判断二叉树。根据题目描述的性质,我们要进行如下三点判断 
1、根节点是否为正数 
2、节点为负数,节点的孩子是否为正数(这里判断当前节点的左右孩子是否为正数) 
3、从任一节点到叶子节点所有路径拥有相同的黑色节点 

 此题包括二叉树的基本操作:BST建树、后序遍历求树高、先序遍历。

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<vector>
 4 using namespace std;
 5 
 6 struct Node {
 7     int data;
 8     Node* lchild;
 9     Node* rchild;
10 };
11 const int maxn = 50;
12 vector<int> pre;
13 
14 //建立二叉查找树
15 void insert(Node *&root,int x) {
16     if(root == NULL) {
17         root = new Node;
18         root->data = x;
19         root->lchild = root->rchild = NULL;
20         return ;
21     }
22     else if(abs(x) < abs(root->data))
23         insert(root->lchild,x);
24     else
25         insert(root->rchild,x);
26 }
27 
28 bool judge1(Node* root) { //判断性质4
29     if(root == NULL) return true;
30     if(root->data < 0) {
31         if(root->lchild != NULL&& root->lchild->data < 0) return false;
32         if(root->rchild != NULL&& root->rchild->data < 0) return false;
33     }
34     return judge1(root->lchild)&&judge1(root->rchild);
35 }
36 
37 int getNum(Node* root) { //后序遍历,求当前二叉树的高度
38     if(root == NULL) return 0;
39     int l = getNum(root->lchild);
40     int r = getNum(root->rchild);
41     return root->data>0?max(l,r)+1:max(l,r);//如果是黑色结点,高度加一
42 }
43 
44 bool judge2(Node* root) { //判断性质5
45     if(root == NULL) return true;
46     int l = getNum(root->lchild);
47     int r = getNum(root->rchild);
48     if(l!=r) return false;
49     return judge2(root->lchild)&&judge2(root->rchild);
50 }
51 int main() {
52     int k,n;
53     cin>>k;
54     while(k--) {
55         cin>>n;
56         pre.resize(n);
57         Node* root = NULL; //记得赋初值 
58         for(int i = 0; i < n; ++i) {//建立BST
59             cin>>pre[i];
60             insert(root,pre[i]);
61         }
62         if(pre[0] < 0 || !judge1(root) || !judge2(root)) printf("No\n");//判断性质2、4、5
63         else printf("Yes\n");
64     }
65     return 0;
66 }

 

方法二:在建立二叉树过程中,依次判断各个性质的合法性

如何判断二叉树。根据题目描述的性质,我们要进行如下三点判断 
1、根节点是否为正数 
2、节点为负数,节点的孩子是否为正数(这里判断如果当前节点是负数,其父亲节点是否也为负数) 
3、从根节点到叶子节点所有路径拥有相同的黑色节点 

注意:如果继续采用方法一中对判断点2进行判断的方法,将会导致测试点2,3答案错误。两种判断方法从理论上来说应该是等价的,但是不知道为什么,两个的答案不一样。

 1 #include<iostream>
 2 #include<vector>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn = 40;
 6 int maxNum;
 7 vector<int> pre,in;
 8 
 9 bool isRedBlackTree(int preL,int preR,int inL,int inR,int num,int father) {
10     if(inL > inR) { //空结点,在红黑树称为叶子结点,性质3
11         if(maxNum == -1) maxNum = num;
12         else if(maxNum != num) return false;
13         return true;
14     }
15     if(pre[father] < 0 && pre[preL] < 0) return false; //判断性质4
16     if(pre[preL] > 0) num++; //黑色结点个数加一 
17     int k,leftNum;
18     for(k = inL; k <= inR; ++k) if(in[k] == abs(pre[preL])) break;
19     leftNum = k-inL;
20     return isRedBlackTree(preL+1,preL+leftNum,inL,k-1,num,preL)&&isRedBlackTree(preL+leftNum+1,preR,k+1,inR,num,preL);
21 }
22 
23 
24 int main() {
25     int k,n;
26     cin>>k;
27     while(k--) {
28         cin>>n;
29         pre.resize(n),in.resize(n);//vector分配空间
30         for(int i = 0; i < n; ++i) {
31             cin>>pre[i];
32             in[i] = abs(pre[i]);
33         }
34         sort(in.begin(),in.end());
35         maxNum = -1;
36         if(pre[0] < 0 || !isRedBlackTree(0,n-1,0,n-1,0,0)) printf("No\n");
37         else printf("Yes\n");
38     }
39     return 0;
40 }

 PS:为了永远避免由分配数组空间导致段错误、溢出、甚至答案错误的问题,以后一律 定义全局vector容器 和 使用resize函数分配vector空间。

posted @ 2020-03-16 22:23  tangq123  阅读(909)  评论(0)    收藏  举报