链接:1135. Is It A Red-Black Tree (30)
红黑树的性质:
(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.
翻译:
(1)红黑树节点只能为红或者黑
(2)根节点是黑
(3)null为黑,表示叶子节点(没有child的节点为叶子节点)可以为红为黑。如果条件改为null节点为红,则叶子节点必须为黑。
(4)如果该节点为红,child节点都为黑。
(5)从根节点到叶子节点的每条路径上的总black节点数都相等。第5点的原意是每个节点到叶子节点的路径上的black节点数都相等,跟根节点到叶子节点的意思一样,而且从根节点计算更方便。因为每个节点到叶子节点上的路径都是根节点到叶子节点路径的一部分。
吐槽:这次PAT考试由于延考一个小时,又加上临时该题,题目出的真的不咋地,4道题目都是题意不清,全靠不断的猜和提交代码测试,才逐渐摸索出题意。虽然只考了91分,但是没接触过红黑树,做不出也可以原谅哈。
理解了红黑树的性质,题目就变得简单,第一步根据先序遍历构造数,由于红黑树是BST树(BST的性质:左孩子比父节点小,右孩子比父节点大),所以已知一个先序就可以很快的构造了。第二步使用dfs来判断是否红黑树就行了。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> using namespace std; int n,a[100]; struct Node { int val; int bBlack; int lBlackNum; int rBlackNum; int tBlackNum; Node* left; Node* right; Node() { left = right = 0; lBlackNum = rBlackNum = tBlackNum = 0; } void setVal(int iVal) { if(iVal > 0) bBlack = 1; else if(iVal < 0)bBlack = 0; val = abs(iVal); } }; Node* CreateTree(int l,int r) { if(l > r) return NULL; Node* nd = new Node(); nd -> setVal(a[l]); int i = l+1; for(;i<=r;++i) if(abs(a[i]) > abs(a[l])) break; nd -> left = CreateTree(l+1,i-1); nd -> right = CreateTree(i,r); return nd; } void DelTree(Node **nd) { if(*nd == NULL) return; DelTree(&(*nd)->left); DelTree(&(*nd)->right); delete *nd; *nd = 0; } bool bIsTree = true; int lastnum = -1; void dfs(Node* nd,int cnt) { if(!bIsTree) return; if(nd == NULL) { if(lastnum == -1) lastnum = cnt; else if(lastnum != cnt){bIsTree = false;} return; } if(nd->bBlack) ++cnt; else { if(nd->left&&!nd->left->bBlack) bIsTree = false; if(nd->right&&!nd->right->bBlack) bIsTree = false; } dfs(nd->left,cnt); dfs(nd->right,cnt); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;++i) scanf("%d",&a[i]); Node* root = CreateTree(0,n-1); bIsTree = root->bBlack; lastnum = -1; //初始化会忘 dfs(root,0); if(bIsTree) printf("Yes\n"); else printf("No\n"); DelTree(&root); //清理内存也很重要,因为很多公司会看代码,这一行代码有加分。 } return 0; }
以下是一种更加简便的创建红黑树的方法,判断过程不变。该方法由同样热爱编程的网友提供。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> using namespace std; struct Node { int val; int bBlack; Node* left; Node* right; Node() { left = right = 0; } void setVal(int iVal) { if(iVal > 0) bBlack = 1; else if(iVal < 0)bBlack = 0; val = abs(iVal); } }; Node* Insert(Node *root,int val) { if(NULL == root){ root = new Node(); root->setVal(val); return root; } if(abs(val) < root->val){ root->left = Insert(root->left,val); }else root->right = Insert(root->right,val); return root; } void DelTree(Node **nd) { if(*nd == NULL) return; DelTree(&(*nd)->left); DelTree(&(*nd)->right); delete *nd; *nd = 0; } bool bIsTree = true; int lastnum = -1; void dfs(Node* nd,int cnt) { if(!bIsTree) return; if(nd == NULL) { if(lastnum == -1) lastnum = cnt; else if(lastnum != cnt){bIsTree = false;} return; } if(nd->bBlack) ++cnt; else { if(nd->left&&!nd->left->bBlack) bIsTree = false; if(nd->right&&!nd->right->bBlack) bIsTree = false; } dfs(nd->left,cnt); dfs(nd->right,cnt); } int main() { int t; scanf("%d",&t); while(t--) { int a,n; scanf("%d",&n); Node* root = NULL; for(int i=0;i<n;++i) { scanf("%d",&a); root = Insert(root,a); } bIsTree = root->bBlack; lastnum = -1; //初始化会忘 dfs(root,0); if(bIsTree) printf("Yes\n"); else printf("No\n"); DelTree(&root); //清理内存也很重要,因为很多公司会看代码,这一行代码有加分。 } return 0; }