后序中序还原二叉树

题目:

样例:

输入
6
1 4 2 3 5 0
1 2 4 0 5 3

输出
0 2 1 4 5 3

思路:

        在这里,要懂得 后序遍历 以及 中序遍历 的性质特征,也就是  中序的左支树节点数量必定是后序数组 的 前面相同数量 上的各个节点。 中序的 右支树 是 后序数组 随后的 剩余的各个结点

这里唯一的难点,就是如何确定 建树的 范围,特别是 右支树

左支树很简单,因为就是前几个

所以 

 len = mid - il


l[root] = biuld(il,il + len - 1,ll,ll + len - 1);

 ir = il + len - 1

 lr = ll + len - 1

而到了右支树

r[root] = biuld(il + len + 1,ir,ll + len,lr - 1);

 这里的  il = il + len + 1  是因为 我们 中序中 mid 以及取出来了 
 所以  il = il + (len - 1) + 2 = il + len + 1

 而后序数组中  

 ll = ll + len    是因为 它不像 中序数组是已经取出来了  所以我们还是要取到该点

 所以 ll = ll + (len - 1) + 1  

详解代码如下:

#include <iostream>
#include <unordered_map>
#define umap unordered_map
using namespace std;

const int N = 500;

int n;	// 结点数量

int last[N];	// 后序数组
int ines[N];	// 中序数组

umap<int,int>l,r,pos;	// l 为左支树的结点 r 为右支树的结点 pos 为某节点在 中序数组的 下标

inline int biuld(int il,int ir,int ll,int lr)
{
	int root = last[lr];	// 根据 后序遍历的性质特征 取得结点

	int mid = pos[root];	// 取得 该节点 在 中序数组的下标

	int len = mid - il;		// 取得 左支树的 结点数量,也是需要递归查找 后序数组 的长度
	
	// cout << mid << endl;

	if(il < mid)	// 如果 中序数组的 左端点 比 该节点 在 中序数组的下标还要小,说明还可以进行查找
	{
		// 结合 中序遍历 和 后序遍历 的性质特征 ,推出 该结点的 左支树,左节点是多少
		l[root] = biuld(il,il + len - 1,ll,ll + len - 1);
	}

	if(ir > mid)	// 如果 中序数组的 右端点 比 该节点 在 中序数组的下标还要大,说明还可以进行查找
	{
		// 结合 中序遍历 和 后序遍历 的性质特征 ,推出 该结点的 右支树,右节点是多少
		r[root] = biuld(il + len + 1,ir,ll + len,lr - 1);
	}

	return root;	// 返回所取得的节点
}

inline void preorder(int root)	// 前序遍历
{
	cout << root;
	if(--n) putchar(' ');	// 控制输出格式
	if(l[root]) preorder(l[root]);
	if(r[root]) preorder(r[root]);	
}

int main()
{
	cin >> n;

	for(int i = 0;i < n;++i) cin >> last[i];

	for(int i = 0;i < n;++i)
	{
		cin >> ines[i];
		pos[ines[i]] = i;	// 存储 中序数组 的各个节点的下标
	}

	int root = biuld(0,n -1 ,0,n - 1);	// 开始建树,并取得根节点

	preorder(root);

	return 0;
}

所以最后提交:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值