1. 程式人生 > >PAT-ADVANCED1135——Is It A Red-Black Tree

PAT-ADVANCED1135——Is It A Red-Black Tree

題目描述:

題目翻譯:

1135 這是一棵紅黑樹嗎

在資料結構中有一種稱為紅黑樹的平衡二叉搜尋樹。 它有以下5個屬性:

(1)每個節點都是紅色或黑色。
(2)根是黑色的。
(3)每個葉子(NULL)都是黑色的。
(4)如果一個節點是紅色的,那麼它的兩個孩子都是黑色的。
(5)對於每個節點,從節點到後代葉子的所有簡單路徑包含相同數量的黑色節點。

例如,圖1中的樹是紅黑樹,而圖2和3中的樹則不是。

對於每個給定的二叉搜尋樹,你需要指出它是否是合法的紅黑樹。

輸入格式:

每個輸入檔案包含幾個測試用例。第一行給出正整數K(<= 30),即測試用例總數。對於每種情況,第一行給出正整數N(<= 30),即二叉樹中的節點總數。第二行給出樹的前序遍歷序列。雖然樹中的所有鍵都是正整數,但我們使用負號來表示紅色節點。一行中的所有數字都用空格分隔。樣例輸入對應於圖1,2和3中所示的樹。

輸出格式:

對每個測試用例,如果該樹是一棵紅黑樹,則列印“Yes”,否則列印“No”。

輸入樣例:

3
9
7 -2 1 5 -4 -11 8 14 -15
9
11 -2 1 -7 5 -4 8 14 -15
8
10 -7 5 -6 8 15 -11 17

輸出樣例:

Yes
No
No

知識點:根據前序遍歷重建二分搜尋樹、樹的深度優先遍歷

思路:先根據前序遍歷重建二分搜尋樹,再深度優先遍歷判斷其是否是一棵紅黑樹

重建二分搜尋樹時,我們比較的應該是其絕對值,因為負號僅代表該節點是紅色,不代表節點大小。來看紅黑樹的5個條件:

(1)條件1,題目自動滿足。

(2)條件2,直接判斷所建樹的根結點是否是正數即可。

(3)條件3,無需判斷。

(4)條件4,dfs過程中一旦出現了紅節點(即負數節點),如果其有左孩子或右孩子,判斷其是否是黑色即可。

(5)條件5,dfs記錄到葉子節點的每條路徑,遞迴終止時,判斷路徑上負數節點的個數,將個數存入set集合countBlack中,利用set集合的去重特性來判斷樹中每個節點到葉子所經過的黑色節點數是否相等。如果最後countBlack中只有一個元素,說明每個節點到葉子所經過的黑色節點數均相等,滿足該條件,否則不滿足該條件。

C++程式碼:

#include<iostream>
#include<vector>
#include<set>
#include<cmath>

using namespace std;

struct node {
	int data;
	node* lchild;
	node* rchild;
};

set<int> countBlack;
vector<int> tempPath;

node* create(vector<int> levelOrder);
void dfs(node* nowVisit, bool &flag);
bool isRBTree(node* head);

int main() {
	int K;
	scanf("%d", &K);
	for(int i = 0; i < K; i++) {
		int N;
		scanf("%d", &N);
		vector<int> levelOrder;
		int num;
		for(int j = 0; j < N; j++) {
			scanf("%d", &num);
			levelOrder.push_back(num);
		}
		node* head = create(levelOrder);
		if(isRBTree(head)) {
			printf("Yes\n");
		} else {
			printf("No\n");
		}
	}
	return 0;
}

node* create(vector<int> levelOrder) {
	if(levelOrder.size() <= 0) {
		return NULL;
	}
	node* head = new node();
	head->data = levelOrder[0];
	vector<int> left;
	vector<int> right;
	for(int i = 1; i < levelOrder.size(); i++) {
		if(abs(levelOrder[i]) < abs(levelOrder[0])) {
			left.push_back(levelOrder[i]);
		} else {
			right.push_back(levelOrder[i]);
		}
	}
	head->lchild = create(left);
	head->rchild = create(right);
	return head;
}

void dfs(node* nowVisit, bool &flag) {
	if(nowVisit == NULL) {
		int count = 0;
		for(int i = 0; i < tempPath.size(); i++) {
			if(tempPath[i] > 0) {
				count++;
			}
		}
		countBlack.insert(count);
		return;
	}
	if(nowVisit->data < 0) {
		if(nowVisit->lchild != NULL) {
			if(nowVisit->lchild->data < 0) {
				flag = false;
			}
		}
		if(nowVisit->rchild != NULL) {
			if(nowVisit->rchild->data < 0) {
				flag = false;
			}
		}
	}
	tempPath.push_back(nowVisit->data);
	dfs(nowVisit->lchild, flag);
	dfs(nowVisit->rchild, flag);
	tempPath.pop_back();
}

bool isRBTree(node* head) {
	if(head->data < 0) {
		return false;
	}
	bool flag = true;
	countBlack.clear();
	tempPath.clear();
	dfs(head, flag);
	if(countBlack.size() != 1 || !flag) {
		return false;
	}
	return true;
}

C++解題報告: