鏈接: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;
}
