方法一、建树,再dfs搜(已知中序和先序,求后序)
P1827 [USACO3.4] 美国血统 American Heritage
#include
using namespace std;
char first;
int length;
string preorder, inorder;
//a[1]['C']='B', 表示'C'的左儿子是'B'
//a[2]['C']='G', 表示'C'的右儿子是'G'
map a[3];
//s1 e1表示中序遍历序列的起终点下标
//s2 e2表示前序遍历序列的起终点下标
//对树的中序遍历、先序遍历进行递归, 找出每个结点的左右儿子
void dfs(int s1, int e1, int s2, int e2)
{
int rootid, leftnum=0;
if(s1==e1 || s2==e2){ //*表示为空
a[1][inorder[s1]]=a[2][inorder[s1]]='*';
a[1][preorder[s2]]=a[2][preorder[s2]]='*';
return;
}
//找到根
char root=preorder[s2];
//在中序遍历中找到根的下标
for(int i=s1; i<=e1; ++i){
leftnum++; //左子树的结点数(包含root)
if(inorder[i]==root){
rootid=i;
break;
}
}
//root根有左儿子
if(rootid>s1){
//记录左儿子
a[1][root]=preorder[s2+1];
//对左子树的中序遍历、先序遍历进行递归, 找出每个结点的左右儿子
dfs(s1, rootid-1, s2+1, s2+leftnum-1);
}
else{
a[1][root]='*';
}
//root根有右儿子
if(rootid> inorder >> preorder;
first=preorder[0]; //二叉树的根节点
length=inorder.length();
dfs(0, length-1, 0, length-1); //注意length-1
postorder(first); //递归求后序遍历
return 0;
}
方法二、直接dfs搜(已知中序和后序,求前序)
P1305 新二叉树
#include
using namespace std;
string in_order, post_order;
int len;
//中序 从l1到r1,后序从l2到r2
void dfs(int l1, int r1, int l2, int r2)
{
int flag;
//剪枝,已经没有节点了,树为空
if(l1>r1 || l2>r2) return;
//后序遍历最后一个肯定是根节点
char root=post_order[r2];
//输出根结点
cout << root;
//在中根遍历序列中找到根结点所在的位置,即可将结点分为左子树和右子树
for(int i=l1; i<=r1; ++i){
if(in_order[i]==root){ //如果等于根
//flag记录的是中序遍历序列中,根结点的位置
//在中根序列中,l1到flag-1的节点都属于左子树,
//flag+1到r1的节点都属于右子树
flag=i;
break;
}
}
//现在问题的关键是如何找出新的左子树的后序遍历序列、新的右子树的后续遍历序列
//原来的后续遍历序列前面部分是左子树的后续序列,紧接着是右子树的后续序列,最后是跟结点
//所以需要知道左子树有多少个结点。
int left_node=flag-l1;
//左子树有left_node个结点,则在后续遍历序列中,左子树的范围是从l2到l2+left_node-1
//紧接着就是右子树,则在后续遍历序列中,右子树的范围是从l2+left_node到r2-1
if(l1> in_order >> post_order;
len=in_order.length(); //获取结点的数量
//中序从0到len-1, 后序从0到len-1
dfs(0, len-1, 0, len-1);
return 0;
}