1. 程式人生 > >PAT-ADVANCED1020——Tree Traversals

PAT-ADVANCED1020——Tree Traversals

我的PAT-ADVANCED程式碼倉:https://github.com/617076674/PAT-ADVANCED

原題連結:https://pintia.cn/problem-sets/994805342720868352/problems/994805485033603072

題目描述:

題目翻譯:

1020 樹的遍歷

假設二叉樹節點上的所有值都是不同的正整數。給你一棵二叉樹的後序遍歷和中序遍歷結果,你需要給出其層序遍歷結果。

輸入格式:

每個輸入檔案包含一個測試用例。在每個測試用例中,第一行給出一個正整數N(<= 30),代表二叉樹的節點個數。第二行給出後序遍歷結果,第三行給出中序遍歷結果。一行中所有的數字由一個空格分隔。

輸出格式:

對每個測試用例,在一行中打印出這課二叉樹的層序遍歷結果。一行中所有的數字必須以一個空格分隔,行末不得有多餘空格。

輸入樣例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

輸出樣例:

4 1 6 3 5 7 2

知識點:二叉樹的後序遍歷、層序遍歷、中序遍歷

思路一:指標實現

中序遍歷可以與前序遍歷、後序遍歷、層序遍歷中的任意一來構建一棵唯一的二叉樹,而後三者兩兩搭配或是三個一起上都無法構建唯一的二叉樹。原因是前序、後序、層序均是提供根節點,作用是相同的,都必須由中序遍歷來區分出左右子樹

時間複雜度與這課二叉樹的構成有關,最壞情況是退化成一個連結串列,是O(N)的複雜度,最好情況是一顆平衡二叉樹,是O(logN)的複雜度。空間複雜度是O(N)。

C++程式碼:

#include<iostream>
#include<queue> 

using namespace std;

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

int N;	//二叉樹的節點個數
int postOrder[31];	//後序遍歷陣列 
int inOrder[31];	//中序遍歷陣列
int levelOrder[31];
int index = 0; 

/*
	當前後序序列區間為[leftPost, rightPost],中序序列區間為[leftIn, rightIn],返回根節點地址 
*/ 
node* create(int leftPost, int rightPost, int leftIn, int rightIn);

/*
	層序遍歷二叉樹 
*/
void levelTraversal(node* root);

int main(){
	cin >> N;
	for(int i = 0; i < N; i++){
		cin >> postOrder[i];
	}
	for(int i = 0; i < N; i++){
		cin >> inOrder[i];
	}
	node* root = create(0, N - 1, 0, N - 1);	//這裡右邊界是N - 1,而不是N,在函式的定義中,左右邊界都是閉區間 
	levelTraversal(root);
	for(int i = 0; i < N; i++){
		cout << levelOrder[i];
		if(i != N - 1){
			cout << " ";
		}
	}
	cout << endl;
	return 0;
}

node* create(int leftPost, int rightPost, int leftIn, int rightIn){
	if(leftPost > rightPost){
		return NULL;	//後序序列的長度小於等於0時,直接返回 
	}
	node* root = new node;
	root->data = postOrder[rightPost];	//新節點的資料域為根結點的值
	int k;
	for(k = leftIn; k <= rightIn; k++){
		if(inOrder[k] == postOrder[rightPost]){
			break;
		}
	}
	int numLeft = k - leftIn;	//左子樹的節點個數
	root->lchild = create(leftPost, leftPost + numLeft - 1, leftIn, k - 1);
	root->rchild = create(leftPost + numLeft, rightPost - 1, k + 1, rightIn);
	return root; 
}

void levelTraversal(node* root){
	if(root == NULL){
		return;
	}
	queue<node*> q;
	q.push(root);
	while(!q.empty()){
		node* now = q.front();
		q.pop();
		levelOrder[index++] = now->data;
		if(now->lchild != NULL){
			q.push(now->lchild);
		}
		if(now->rchild != NULL){
			q.push(now->rchild);
		}
	}
}

C++解題報告:

思路二:靜態陣列實現

建立一個大小為節點上限個數的node型陣列,所有動態生成的節點都直接使用陣列中的節點,所有對指標的操作都改為對陣列下標的訪問。

C++程式碼:

#include<iostream>
#include<queue>

using namespace std;

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

int N;	//二叉樹的節點個數
int postOrder[31];	//後序遍歷陣列 
int inOrder[31];	//中序遍歷陣列
int levelOrder[31];	//層序遍歷陣列
node Node[31];
int index = 0;
int resultIndex = 0;

int create(int leftPost, int rightPost, int leftIn, int rightIn);
void levelTraversal(int root); 

int main(){
	cin >> N;
	for(int i = 0; i < N; i++){
		cin >> postOrder[i];
	}
	for(int i = 0; i < N; i++){
		cin >> inOrder[i];
	}
	int root = create(0, N - 1, 0, N - 1);
	levelTraversal(root);
	for(int i = 0; i < N; i++){
		cout << levelOrder[i];
		if(i != N - 1){
			cout << " ";
		}
	}
	cout << endl;
	return 0;
}

int create(int leftPost, int rightPost, int leftIn, int rightIn){
	if(leftPost > rightPost){
		return -1;
	}
	int root = index++;
	Node[root].data = postOrder[rightPost];
	int k;
	for(k = leftIn; k <= rightIn; k++){
		if(inOrder[k] == postOrder[rightPost]){
			break;
		}
	}
	int numLeft = k - leftIn; 
	Node[root].lchild = create(leftPost, leftPost + numLeft - 1, leftIn, k - 1);
	Node[root].rchild = create(leftPost + numLeft, rightPost - 1, k + 1, rightIn);
	return root ;
}

void levelTraversal(int root){
	if(root == -1){
		return;
	}
	queue<int> q;
	q.push(root);
	while(!q.empty()){
		int now = q.front();
		q.pop();
		levelOrder[resultIndex++] = Node[now].data;
		if(Node[now].lchild != -1){
			q.push(Node[now].lchild);
		}
		if(Node[now].rchild != -1){
			q.push(Node[now].rchild);
		}
	}
}

C++解題報告: