先序中序还原二叉树

本文介绍了如何利用前序遍历和中序遍历的特性,通过递归方法在数据范围内构建二叉树,特别关注了左支树和右支树的数据范围计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

样例:

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

输出
1 4 2 3 5 0

思路:

        结合前序的性质特征,中序的性质特征,前序遍历的时候,前面的第一个结点,结合中序数组可以推出,第一个结点是确定结点,而后确定结点在中序数组中,左边的结点数量就是在前序数组该节点往后的相同数量。

在这里唯一的一个重难点还是那个数据范围:

递归 左支树操作

// 判断是否有左支树, 结合前序和中序的特征性质,计算相应的数据范围,递归查找结点
if(il < mid) l[root] = biuld(il,il + len - 1,pl + 1,pl + len - 1);

在这里 中序的数据范围,还是那个判断长度

不同点的是 前序数组范围 pl 是  pl + 1

是因为  pl 是我们已经取得到了的结点 root = pre[pl]

随后前序的右边数据范围 就是 加上我们计算到的长度  即 pr = pl + len - 1

递归 右支树操作

// 判断是否有右支树, 结合前序和中序的特征性质,计算相应的数据范围,递归查找结点
	if(ir > mid) r[root] = biuld(il + len + 1,ir,pl + len + 1,pr);

在这里,中序的数据范围还是之前那样根据计算的长度推算

不同的是 这里的 pl 为什么不是 pl + len ,是因为 我们 pl 已经取得了 root 

所以我们一定要记得 pl + len + 1,  因为

原来的左支树的前序右边的范围 是  pl + len - 1

所以我们右支树的前序左边的范围是   pl = (pl + len - 1) + 1 = pl + len

但是我们 前序左边的端点已经是 取得了 root = pre[(pl + len)]  所以我们递归的时候记得

pl = (pl + len - 1) + 1 + 1 = pl + len + 1

代码详解如下:

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

const int N = 500;

int n;	// 结点数量

int pre[N];	// 先序数组
int ines[N];	// 中序数组

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

inline int biuld(int il,int ir,int pl,int pr)
{
	// 根据前序遍历特征性质,取得确定的结点
	int root = pre[pl];

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

	int len = mid - il;		// 计算 左支树的结点数量

	// 判断是否有左支树, 结合前序和中序的特征性质,计算相应的数据范围,递归查找结点
	if(il < mid) l[root] = biuld(il,il + len - 1,pl + 1,pl + len - 1);

	// 判断是否有右支树, 结合前序和中序的特征性质,计算相应的数据范围,递归查找结点
	if(ir > mid) r[root] = biuld(il + len + 1,ir,pl + len + 1,pr);

	return root;	// 返回取得确定的结点
}

inline void lastorder(int root)
{
	if(l[root]) lastorder(l[root]);

	if(r[root]) lastorder(r[root]);
	
	cout << root;

	if(--n) putchar(' ');	// 控制输出格式

}

int main()
{
	cin >> n;

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

	for(int i = 0;i < n;++i)
	{
		cin >> ines[i];
		pos[ines[i]] = i;
	}

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

	return 0;
}

 最后提交:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值