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空间。