1916:【01NOIP普及组】求先序排列(树的经典题)

http://ybt.ssoier.cn:8088/problem_show.php?pid=1916

1916:【01NOIP普及组】求先序排列

【题目描述】
给出一棵二叉树的中序与后序排序。求出它的先序排列。(约定树结点用不同的大写字母表示,长度≤8)。

【输入】
一行,一棵二叉树的中序与后序排序,中间用一个空格隔开。

【输出】
它的先序排列

【输入样例】
BADC BDCA
【输出样例】
ABCD

这是一道已知中序和后序,求先序的程序。我将用递归的方法来讲解这一道题。刷到现在,发现做题是一件及其有意思的一件事。我希望把这种快乐传递给更多的人,哈哈哈哈哈。

1.关于先序遍历、中序遍历和后序遍历的遍历顺序在(https://blog.csdn.net/qq_39053800/article/details/108182882)这个题目中已写,大家可以去这边求后序遍历的文章中去看。

2.根据中序遍历的访问顺序可以得知,它的根结点、左子树和右子树是非常好找的,比如,中序遍历的起点是L1,终点是r1;
定义pos为根结点的下标
那么,中序遍历的左子树起止范围:(L1, pos-1) ,右子树起止范围:(pos+1, R1)
就是根结点pos将其分为左右两边,左边就是左子树,右边就是右子树。

3.后序遍历的左子树和右子树不好找,难点在于找到后序遍历中的左子树和右子树边界
睁大眼睛看好啦,哈哈哈哈
根据中序遍历的定义,得知
左子树长度:pos-L1;
右子树长度:R1-pos;

规定后序遍历的起点是L2,终点是R2;

后序遍历左子树的边界分析如下:
起点:L2;
终点有两种计算方法:第一种:(起点+左子树长度-1) L2+(pos-L1)-1;
终点有两种计算方法:第二种:(终点-右子树长度-1) R2-(R1-pos)-1(因为最后一个为根,所以要-1);

后序遍历右子树的边界分析如下:
因为左子树的终点有两种方法,那么右子树就有两种写法。
第一种:
起点:(第一种方法起点+1)L2+(pos-L1);
终点:(起点+右子树长度-1)L2+(pos-L1)+(R1-pos)-1 = L2-L1+R1-1;
第二种:
起点:(第二种方法起点+1)R2-(R1-pos);
终点:(起点+右子树长度-1)R2-(R1-pos)+(R1-pos)-1 = R2-1;

确定好左右子树的边界以后,递归就很好写了,所以递归就有两种写法:
第一种:
if(pos > L1) dg(L1, pos-1, L2, L2+(pos-L1)-1);//递归左子树
if(pos < R1) dg(pos+1, R1, L2+(pos-L1), L2-L1+R1-1);//递归右子树
第二种:
if(pos > L1) dg(L1, pos-1, L2, R2-(R1-pos)-1);//递归左子树
if(pos < R1) dg(pos+1, R1, R2-(R1-pos), R2-1);//递归右子树

#include<bits/stdc++.h>
using namespace std;
string between, after;
//pos-l1:左子树长度
//r1-pos:右子树长度
void dg(int l1, int r1, int l2, int r2){
	int pos = between.find(after[r2]);
	cout << between[pos];
	if(pos > l1) dg(l1, pos-1, l2, r2-r1+pos-1);//递归左子树
	if(pos < r1) dg(pos+1, r1, r2-r1+pos, r2-1);//递归右子树
}
int main(){
	cin >> between >> after;
	dg(0, between.size()-1, 0, after.size()-1);
	return 0;
}

欢迎点赞和评论

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值