(PAT Advanced) 1020.Tree Traversals (二叉树的后序中序转前序) C++

原题:https://pintia.cn/problemsets/994805342720868352/problems/994805519074574336

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

题目分析:
由二叉树的后序遍历(postorder)和中序遍历(inorder)建立二叉树,并进行层次遍历。
即后序(左右根)找出根结点,中序(左根右)划分左右子树。

风格一
一步一步按照建立二叉树和层次遍历进行,建立二叉树用递归,层次遍历用队列:

/* 1020 Tree Traversals (25 分) */
#include<iostream>
#include<queue>

using namespace std;

int PostOrder[30]; // 后序
int Inorder[30]; // 中序
int Len;         // 输入的树的结点数
int flag = 1;    // 是否为输出的第一个

typedef struct node {
	int data;
	struct node* left;
	struct node* right;
}BNode,*BTree;

// 解法,后序(左右根)找根,中序(左根右)进行递归
int FindElem(int* arr, int e, int len) {
	// 在数组arr中找e的索引
	int i;
	for (i = 0; i < len && arr[i] != e; i++);
	if (i == len) return -1;
	else return i;
}
int FindRoot(int start, int end) {
	// 从Inorder[start,...,end]中找根,返回下标
	// 比较谁在PostOrder中的索引靠后
	int root = Inorder[start];
	int root_index = start;
	int index = FindElem(PostOrder, root,Len);
	for (int i = start + 1; i <= end; i++) {
		int index_ = FindElem(PostOrder, Inorder[i], Len);
		if (index_ > index) {
			root = Inorder[i];
			root_index = i;
			index = index_;
		}
	}
	return root_index;
}
void CreateTree(int start, int end, BTree& T) {
	// T表示根
	if (end < start || start > end) {
		T = NULL;  // 注意这里T是会变化的,所以需要用引用传递的方式
		return;
	}
	int root = FindRoot(start, end);
	T->left = (BNode*)malloc(sizeof(BNode));
	T->right = (BNode*)malloc(sizeof(BNode));
	T->data = Inorder[root];
	CreateTree(start, root - 1, T->left);
	CreateTree(root + 1, end, T->right);
}

void LevelTravel(BTree T) {
	// 树T的层次遍历
	queue<BTree> Q; // 遍历的结点队列
	Q.push(T);
	while (!Q.empty()) {
		BTree e;
		e = Q.front(); Q.pop();
		if (flag == 0) {
			printf(" ");
		}
		printf("%d", e->data);
		flag = 0;
		if (e->left) Q.push(e->left);
		if (e->right) Q.push(e->right);
	}
}
int main() {
	scanf("%d", &Len);
	int i;
	for (i = 0; i < Len; i++) scanf("%d", &PostOrder[i]);
	for (i = 0; i < Len; i++) scanf("%d", &Inorder[i]);
	BTree T;
	T = (BNode*)malloc(sizeof(BNode));
	T->left = T->right = NULL;
	CreateTree(0, Len - 1, T);
	LevelTravel(T);
	system("pause");
	return 0;
}

风格二(简化)
同样是先根遍历建立二叉树,但是由后序遍历和中序遍历建立先序遍历的时候利用索引进行简化。
假设结点数组开始于start,结束于end。
因为后序遍历的最后一个总是树的根结点,记其在Post中索引为 r o o t root root,所以假设在中序遍历中该结点下标为 i i i,则右子树共有 ( e n d − i + 1 ) (end-i+1) (endi+1)个结点。所以在后序中根结点为 r o o t root root,右子树的根节点为 r o o t − 1 root-1 root1 ,左子树的根结点为 r o o t − ( e n d − i + 1 ) = ( r o o t − e n d + i − 1 ) root-(end-i+1) = (root-end+i-1) root(endi+1)=(rootend+i1)
则有

/* 1020 Tree Traversals (25 分) */
#include<iostream>
#include<queue>

using namespace std;

int Postorder[30]; // 后序
int Inorder[30]; // 中序
int Len;         // 输入的树的结点数
int flag = 1;    // 是否为输出的第一个

typedef struct node {
	int data;
	struct node* left;
	struct node* right;
}BNode, *BTree;

// 后序和中序建立二叉树,即转成先序遍历
void pre(int root,int start, int end, BTree& T) {
	// 注意这里的root是Post中根的索引
	// 二左右子树的划分是在Inorder里,所有start和end是在中序中
	// 现在Inorder中找到根结点
	if (start > end) {
		T = NULL;
		return;
	}
	int i = start;
	while (i < end && Inorder[i] != Postorder[root]) i++;
	T = (BNode*)malloc(sizeof(BNode));
	T->left = T->right = NULL;
	T->data = Postorder[root];
	pre(root - end + i - 1, start, i - 1, T->left); // 左子树
	pre(root - 1, i + 1, end, T->right);            // 右子树
}
void LevelTravel(BTree T) {
	// 树T的层次遍历
	queue<BTree> Q; // 遍历的结点队列
	Q.push(T);
	while (!Q.empty()) {
		BTree e;
		e = Q.front(); Q.pop();
		if (flag == 0) {
			printf(" ");
		}
		printf("%d", e->data);
		flag = 0;
		if (e->left) Q.push(e->left);
		if (e->right) Q.push(e->right);
	}
}
int main() {
	scanf("%d", &Len);
	int i;
	for (i = 0; i < Len; i++) scanf("%d", &Postorder[i]);
	for (i = 0; i < Len; i++) scanf("%d", &Inorder[i]);
	BTree T;
	pre(Len - 1, 0, Len - 1, T);
	LevelTravel(T);
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值