【二叉树的遍历】PAT 1020 Tree Traversals

2 篇文章 0 订阅
1 篇文章 0 订阅

题目链接:

https://pintia.cn/problem-sets/994805342720868352/problems/994805485033603072

题意

给你一颗二叉树的先序遍历和后续遍历,求层次遍历。

思路

对于后续遍历,根据后续遍历的性质,某个子树的根节点即为当前遍历区间结果的的最后一位

如对于子树的后续遍历结果:2 3 1 5 7 6 4。则当前子树的根节点即为4.

同样的,对于中序遍历,根据性质,根节点向左的左区间为当前子树的左子树,根节点向右的右区间为当前子树的右区间。如对于上述子树后续遍历的结果,我们可知当前子树的根节点为4,若当前子树的中序遍历为:1 2 3 4 5 6 7,则当前子树的左区间为123,右区间为567.

那么实现思路就很简单了,反复重复上述两个过程。

  1. 传入根节点,根据中序遍历的结果,找到根节点在中序遍历的位置。
  2. 根据跟节点位置,将当前子树的中序遍历结果分成左右子树。
  3. 根据左右子树的个数,在后序遍历中推算出左右子树根节点。
    • 例如:后序遍历2 3 1 5 7 6 4,中序遍历1 2 3 4 5 6 7.后序遍历根节点为4,在中序中,左子树数量为3,右子树数量为3,则左子树根节点为1,右子树根节点6.
    • 原理很简单,中序遍历可以确定左右子树的个数,而后序遍历的遍历顺序:左子树、右子树、根节点。所以左右子树是聚集而且有序的,所以确定左右子树的个数,就可以根据后续遍历的顺序确定左右子树的根节点。
  4. 回到1,反复直至子树为空。

构建了树,层次遍历就很简单了,使用一个队列,将根节点,左右子树分别入队,之后按顺序出队并反复直到队列为空就好了。

满分代码

/* ***********************************************
Author :Chord
Created Time :2019/10/21 22:10:57
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <stack>
#include <bitset>
#include <iomanip>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
#define EPS 1e-9
int postorder[50], inorder[50],n;
struct node
{
	node *l, *r;
	int value;
	node(){
		l = NULL;
		r = NULL;
		value = -1;
	}
};

void _Find(node* root,int rootIndex, int l, int r) {
	if (l > r)
		return;
	//root = new node();
	//root->value = postorder[r - 1];
	root->value = postorder[rootIndex];
	int i;
	for (i = l; i < r && inorder[i] != postorder[rootIndex]; i++);
	int rnum = r - i;
	auto lson = new node;
	auto rson = new node;
	_Find(lson, rootIndex - rnum - 1,l,i-1);
	_Find(rson, rootIndex - 1, i + 1, r);
	if (lson->value != -1)
		root->l = lson;
	if (rson->value != -1)
		root->r = rson;
}

vector<int>ans;

void test(node *root){
	cout << root->value<<' ';
	if (root->l != NULL)
		test(root->l);
	if (root->r != NULL)
		test(root->r);
}

void order_traversal(node* root) {
	queue<node*>q;
	q.push(root);
	while (!q.empty()) {
		ans.push_back(q.front()->value);
		if (q.front()->l != NULL)
			q.push(q.front()->l);
		if (q.front()->r != NULL)
			q.push(q.front()->r);
		q.pop();
	}
}
 

void solve_PAT1020(void) {
	//freopen("in.txt","r",stdin);
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> postorder[i];
	for (int i = 0; i < n; i++)
		cin >> inorder[i];
	node* root = new node;
	_Find(root, n - 1, 0, n - 1);
	//test(root);
	//cout << endl;
	order_traversal(root);
	for (int i = 0; i < n; i++) {
		cout << ans[i];
		if (i == n - 1)
			cout << endl;
		else
			cout << ' ';
	}
	//freopen("out.txt","w",stdout);
}

int main(void){
    solve_PAT1020();
    return 0;
}

后记

创作于:2019-10-23

说来惭愧,当年pat认证时出了一道基本上一摸一样的原题,就是将本题的先序后序求中序改成了先序中序求后序,结果在认证的时候反而没做出来,还是功夫不到家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

两米长弦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值