二叉樹前序先序後序層序遍歷的轉換

已知後序(postorder)與中序(inorder)輸出先序(preorder)

思路:使用遞歸算法,每次找到post後序子樹根節點在in中序中的位置,numL爲左子樹的長度。

#include <cstdio>
using namespace std;
//測試數據
int post[] = { 3, 4, 2, 6, 5, 1 };
int in[] = { 3, 2, 4, 1, 6, 5 };
void pre(int postL, int postR, int inL, int inR) {
	if (postL > postR) {  //遞歸邊界
		return;
	}
	//查找節點在中序序列中的位置
	int k;
	for (k = inL; k <= inR; k++) {
		if (in[k] == post[postR]) break;
	}
	printf("%d ", post[postR]);
	int numL = k - inL; //左子樹的長度
    //遞歸調用
	pre(postL, postL + numL - 1, inL, k - 1); //從左子樹遞歸到最底層葉子結點,每次遞歸節點都會輸出
	pre(postL + numL, postR - 1, k + 1, inR);
}

int main() {
	pre(0, 5, 0, 5);
	return 0;
}

已知後序(postorder)與中序(inorder)輸出層序(level order)

這是PAT甲級的一道題:1020 Tree Traversals (25分)

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree.

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.

Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding binary tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

Sample Output:
4 1 6 3 5 7 2

這裏參考柳神的算法寫的,還是先轉爲先序,用index標記先序遍歷中的節點號,將其排序輸出後即爲層序遍歷。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node {
	int d; //數據
	int i; //標號
};
bool cmp(node a, node b) {
	return a.i < b.i;
}
int post[30], in[30];
vector<node> v;
void pre(int postL, int postR, int inL, int inR, int index) {
	if (postL > postR) return;
	int k;
	for (k = inL; k <= inR; k++) {
		if (in[k] == post[postR]) break;
	}
	v.push_back({ post[postR],index });
	int numL = k - inL;
	pre(postL, postL + numL - 1, inL, k - 1, index * 2);
	pre(postL + numL, postR - 1, k + 1, inR, index * 2 + 1);
}
int main() {
	int n; cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> post[i];
	}
	for (int i = 0; i < n; i++) {
		cin >> in[i];
	}
	pre(0, n - 1, 0, n - 1, 1); //初始標號爲1
	sort(v.begin(), v.end(), cmp); //標號遞增排序
	for (int i = 0; i < n; i++) {
		if (i == 0) cout << v[i].d;
		else cout << " " << v[i].d;
	}
	return 0;
}

已知先序和後序輸出中序

先序和後序不能唯一確定一個樹,由於當節點只有一個子樹時我們不能確定這是左子樹還是右子樹。因此,本程序依造PAT甲級1119題(點擊這裏),給出瞭解法。

#include <iostream>
#include <vector>
using namespace std;
int pre[30], post[30];
vector<int> I;
bool flag = true; //標記是否唯一,初始爲true

//遞歸實現的函數
//形參依次爲先序、後序在數組中的的起止下標
void in(int preL, int preR, int postL, int postR) {
	if (preL == preR) {
		I.push_back(pre[preL]);  //當節點沒有子樹時
		return;
	}
	//以先序序列爲參考,找子樹根節點在後序序列中的位置
	int k;
	for (k = postL; k <= postR - 1; k++) {
		if (pre[preL + 1] == post[k]) break;
	}
	int numL = k - postL + 1;  //左子樹的長度
	//節點放入容器,從下往上依次放入左兒子、父節點、右兒子
	//若只有一個子樹,則假定爲左子樹,因爲可以通過k<postR-1判斷是否存在右子樹
	in(preL + 1, preL + numL, postL, postL + numL - 1); //遞歸調用,直到遞歸邊界即葉子結點再返回
	I.push_back(pre[preL]); //父節點
	if (k < postR - 1) in(preL + numL + 1, preR, postL + numL, postR - 1); //判斷是否有右子樹,有即加入容器
	else flag = false; //沒有則標記樹不唯一
}

int main() {
	int n; cin >> n;
	for (int i = 0; i < n; i++) cin >> pre[i];
	for (int i = 0; i < n; i++) cin >> post[i];
	in(0, n - 1, 0, n - 1);
	flag ? printf("Yes\n") : printf("No\n");
	for (int i = 0; i < I.size(); i++) {
		if (i == 0) printf("%d", I[i]);
		else printf(" %d", I[i]);
	}
	cout << endl;
	return 0;
}

這裏用的是將先序序列作爲參考,則只能判斷是否存在右子樹。也可以將後序序列作爲參考,此時只能判斷是否存在左子樹,大家可以試試。

已知中序遍歷的棧模擬過程,輸出後序

棧實現的是二叉樹的中序遍歷(左根右),而每次push入值的順序是二叉樹的前序遍歷(根左右),所以可以用二叉樹前序和中序轉後序的方法做。

1086 Tree Traversals Again (25分) 題目描述
Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop

Sample Output:
3 4 2 6 5 1

#include<iostream>
#include<string>
#include<vector>
#include<stack>
using namespace std;
vector<int> pre,in,an; //先序、中序、後序序列(anwser)
void post(int preL, int preR, int inL, int inR) {
	if (preL > preR) {
		return;
	}
	int k;
	for (k = inL; k <= inR; k++) {
		if (in[k] == pre[preL]) break;
	}	
	int numL = k - inL;
	post(preL + 1, preL + numL, inL, k - 1);
	post(preL + numL + 1, preR, k + 1, inR);
	an.push_back(in[k]);
}
int main() {
	int n; cin >> n;
	stack<int> s;
	for (int i = 0; i < n * 2; i++) {
		string str; cin >> str;
		if (str == "Push") {
			int t; cin >> t;
			s.push(t); pre.push_back(t);
		}
		else {
			in.push_back(s.top());
			s.pop();
		}
	}
	post(0, n - 1, 0, n - 1);
	for (int i = 0; i < n; i++) {
		if (i == 0) printf("%d", an[i]);
		else printf(" %d", an[i]);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章