题目描述
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度≤8)。
输入格式
2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。
输出格式
1行,表示一棵二叉树的先序。
输入输出样例
输入 #1
BADC
BDCA
输出 #1
ABCD
题解
近期刚学的树,趁着现在印象比较深,遂写下来。
题意明显,已知二叉树的中序和后序排列,求先序排列。
预备的知识:
先序排列:根左右
中序排列:左根右
后序排列:左右根
也就是什么序,根的位置就在哪里。
已知先序+中序--->后序 ,已知后序+中序--->先序,但已知先序和后序无法推出中序。
案例分析:
二叉树的中序序列:ABCDEFG 后序序列:BDCAFGE
每次都从先序/后序起手,找整个树的根。
后序为“左右根”,遂看最后一个点(先序为最初一点)。确定整个树根节点为 E 。
由于中序为“左根右”,我们把已经确定的 E 放在中序中,E为已知的根,可知 E 左侧为根节点E的左子数,E 右侧为右子数。
通过中序,了解左子数为“ABCD”,右子数为“FG”。
但这仅为其在中序的排列,只看左子数的中序,无法得到它的前序。同样,仅看后序,也无法得到前序。
所以才需要二者对照来看。
找到的左子数序列虽然不能反映前序,但其中包含的字母节点及其数量却是固定的。哪怕放到前序中,也只是在已知几个字母中换换顺序。
这样,已知中序左子数的“ABCD”,便能在后序中找到对应的“BDCA”。
我们找到了一颗子树的中序和前序。
然后呢?我们发现似乎回到了问题的最开始,已知了中后,而要寻找前序,只是这次的序列短了一些。
这种反复的过程怎么实现?自然是递归啦。
同样的,E的右子数也是一样的方法,一样的递归。
ac代码
#include<bits/stdc++.h>
using namespace std;
void tree(string a,string b) //a 中序 b后序
{
if(a.size()==0 || b.size()==0) return;
char ch = b[b.size()-1];
cout<<ch; //根
int root = a.find(ch);
tree(a.substr(0,root),b.substr(0,root)); //左子数
tree(a.substr(root+1),b.substr(root,b.size()-1-root)); //右子数
}
int main()
{
string a,b;
cin>>a;
cin>>b;
tree(a,b);
return 0;
}
到了这题,STL 就显露出它的方便了。
同样的,若是给了先序和中序,要求后序呢?也很简单。
得到什么序,前面进行了微调,后面调整了输出的顺序
代码
#include<bits/stdc++.h>
using namespace std;
void tree(string a,string b) //a 中序 b 先序
{
if(a.size()==0 || b.size()==0) return;
char ch = b[0];
int m = a.find(ch);
tree(a.substr(0,m),b.substr(1,m)); //左子数
tree(a.substr(m+1,a.size()-m-1),b.substr(m+1,b.size()-m-1)); //右子数
cout<<ch; //根
}
int main()
{
string a,b;
cin>>a;
cin>>b;
tree(a,b);
return 0;
}