简单描述
[USACO3.4]美国血统 American Heritage:
中序遍历+前序遍历-------------->后序遍历
P1030 [NOIP2001 普及组] 求先序排列:
中序遍历+后序遍历-------------->前序遍历
二叉树的遍历:
中序遍历+层次遍历-------------->先序序列
这三道题基本上包括了所有类似的问题
求同
这三道题都有共同点
也是关键点
通过中序遍历+其他遍历
来得到要求遍历
(如果是先序序列+后序序列,则不会得到唯一一棵树)
两种思路
- 建树后遍历
- 按照对应要求,建树时输出
存异
不同的地方也显而易见,除了给出的中序遍历相同外,给出的另一种遍历不同
前面思路讲解的比较模糊,这里详细的讲解一下
- 思路实现
以美国血统为例
样例:
中序:ABEDFCHG
前序:CBADEFGH
首先我们需要找出根(无论是那种思路,这是必需的
通过前序的定义(先序先访问的是根),第一个字母C一定是这个二叉树的根
那么中序会分为两部分,左子树{A B E D F},右子树{H G}
(因为中序是先遍历左子树,再访问根,再遍历右子树
由此可以得出根节点左边的是左子树,右边的是右子树
这个时候我们就知道左子树的元素个数为5,右子树元素个数为2
那再由此推出前序部分中左子树{B A D E F},右子树{G H};
这道题的要求为后序遍历,那就继续遍历左子树,直到叶节点
此时的树中序{A B E D F}
此时的树前序{B A D E F}
之前同理
中序部分,左子树{A},右子树{E D F}
前序部分,左子树{A},右子树{D E F}
再遍历左子树
此时的树,无论先序,中序皆为{A}
此时为叶节点,那就可以直接输出A
返回到这个节点的父节点
也就是
中序部分,左子树{A},右子树{E D F}
前序部分,左子树{A},右子树{D E F}
因为左子树遍历完了,在遍历右子树
此时的树
中序部分,右子树{E D F}
前序部分,右子树{D E F}
同理
中序部分,左子树{E},右子树{F}
前序部分,左子树{E},右子树{F}
剩下的请读者尝试模拟,毕竟自己的模拟出来的记得牢
这个时候,可能你已经发现这时递归实现,因为本身遍历就是递归实现
上述模拟的递归code
ft//先序
mt//中序
void lt(int a,int b,int c,int d){
if(a>b || c>d) return ;//需要中序和先序的条件同时满足
int p=mt.find(ft[a]);//寻根的place
//以根的位置把中序遍历分为两部分
lt(a+1,a+p-c,c,p-1);//a+1---a+p-c为先序左子树范围,c----p-1 为中序 //原因:p-c为左子树元素个数
lt(a+p-c+1,b,p+1,d);//a+p+1-c---b为先序右子树范围 ,p+1----q为中序 //原因:b-(p-c+1)为右子树元素个数
cout<<ft[a];
}
但是这个中序遍历+层次遍历的问题,略微有点不同
但上述三道题的根本:确定根,再由根去确定其他节点(当前根的左右子树的根
希望对您有所帮助
- 参考AC code
[USACO3.4]美国血统 American Heritage
建树后后续遍历
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
string ft,mt;
struct node{
char l;
char r;
}t[300];
void lt(int a,</