算法训练 求先序排列
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度<=8)。
输入格式
两行,每行一个字符串,分别表示中序和后序排列
输出格式
一个字符串,表示所求先序排列
样例输入
BADC
BDCA
样例输出
ABCD
前言:虽然这是一道很基础的一道题,但是我看到一种优秀思路,我就想要记录到博客里。
思路与解析:
这是一个给中序和后序求先序的题,我们大概的思想就是在先序中找出和后序最后一个字符(头结点)一样的字符的位置,打印出来,然后他的左面就是左孩子,右面就是右孩子,然后再将左孩子的串递归进去,找根左右,没有左孩子了return回来找右孩子,在将右孩子串找左孩子,递归递归递归 递归……
1、比如我们拿例子中的
中序:BADC
后序:BDCA
首先在中序找到后序的最后一个字符 “A” , 找到他的下标是 1 ,并打印A,因为他是根,然后这时后序就剩DBC,中序分为了左子串“B”和右子串“DC”。
for(int i = 0;i < r1 ;i++) //遍历中序中节点
{
if(a[i] == b[r2 - 1]) //找到和末尾一样的字符
{
printf("%c",a[i]); //打印根
k = i; //记录下标
}
}
2、我们再先后把他的左子树和右子树递归进去
if( k > l1) tree(l1, k, l2, l2 + k - l1);
if(k + 1 < r1) tree(k+1, r1,l2 + k - l1,r2 -1);
k是根节点再中序串中的坐标,那么如果根节点的坐标不在中序串的第一个位置,即 k > l1 ,则代表他还有左孩子,那么就继续访问他的左孩子,那么左孩子的临界坐标应该是 l1和 k (这里为什么是k而不是k - 1,是因为在每次遍历是从i = 0;i < r1 ;i++,所以i 是< k的),右孩子的临界坐标是 l2 和 l2 + k - l1,我们知道后序串中根节点的左孩子一定是从下标为0开始的,因为是左右根嘛,那么左临界是l2没有问题,那么右临界就是从l2开始向右数左孩子的个数,比如左孩子只有一个B,那就是移动一位,即 l2 + k - l1,(k - l1 就代表在根节点之前左孩子长度是多少),那么直到没有左孩子了之后递归出来,开始递归右孩子,同理k+1, r1,l2 + k - l1,r2 -1这四个参数我想也不用多讲,k的下一位到最右面,和左孩子右面开始到最后已经打印过的节点下标之前。
那么到这里已经很详细的说明了递归过程,下面就上完整代码:
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
char a[10];
char b[10];
int tree(int l1,int r1,int l2,int r2)//中序后序开始都是0到r1
{
int k;
for(int i = 0;i < r1 ;i++)
{
if(a[i] == b[r2 - 1]) //找到根
{
printf("%c",a[i]); //打印根
k = i; //记录下标
}
}
if( k > l1) tree(l1, k, l2, l2 + k - l1); //如果有左孩子就一直递归
if(k + 1 < r1) tree(k+1, r1,l2 + k - l1,r2 -1); //左孩子递归完了后开始递归右孩子
}
int main()
{
scanf("%s",a);
scanf("%s",b);
int lenth1 = strlen(a); //length 是中序
int lenth2 = strlen(b); //length 是后序
tree(0,lenth2,0,lenth2);
return 0;
}
在我们学会给出 中 后 算先序,我们再试试给出中 先 算后序(当然不可能是给先后算中序,因为如果没有中序你无法确定左右孩子的位置)
我根据同样的思想也想出了相似的方法:
我们的思想还是一样,首先找到根节点(中序遍历和先序的第一个做 == )
for(int i = 0;i < r1 ;i++)
{
if(a[i] == b[l2])
{
k = i;
}
}
但是找到了并不打印,而是递归他的左右子串,直到最下方的节点已经没有孩子(左右都没有)了,打印该节点
if( k > l1) tree(l1 , k, l2 + 1 , l2 + 1 + k - l1);//cout<<"1";
if(k + 1 < r1) tree(k+1, r1,l2 + 1 + k - l1,r2);
printf("%c",a[k]);
这里的左右临界大家自己去思考一下为什么吧,博主就不再解释了,和上面的大同小异;
完整代码:
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
char a[10];
char b[10];
int tree(int l1,int r1,int l2,int r2)
{
int k;
for(int i = 0;i < r1 ;i++)
{
if(a[i] == b[l2])
{
k = i;
}
}
if( k > l1) tree(l1 , k, l2 + 1 , l2 + 1 + k - l1);//cout<<"1";
if(k + 1 < r1) tree(k+1, r1,l2 + 1 + k - l1,r2);
printf("%c",a[k]);
}
int main()
{
scanf("%s",a);
scanf("%s",b);
int lenth1 = strlen(a);
int lenth2 = strlen(b);
tree(0,lenth2,0,lenth2);
return 0;
}