【题目描述】
树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。
假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,求该树的先序遍历字符串。
【输入】
两行,每行是由字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的中序遍历和按层遍历的序列。
【输出】
一行,表示二叉树的先序序列。
【输入样例】
DBEAC
ABCDE
【输出样例】
ABDEC
因为前面两篇文章介绍了先序遍历、中序遍历和后序遍历的相关定义,所以这里不赘述,,可参考括号内的文章,后面附有链接。
(1339:【例3-4】求后序遍历https://blog.csdn.net/qq_39053800/article/details/108182882主要是把递归左右子树的边界弄清楚)
这里补充说明一下,层次遍历:从第一层(根节点)到最后一层,每层都是逐步从左往右遍历。
因为中序遍历的顺序是先遍历左子树,再访问根结点,最后遍历右子树;
然而层次遍历的顺序是每一层从左往右遍历,再下一层;
然后举例说明(红色字体:中序遍历结点在层次遍历中出现的先后顺序):
那么从以上遍历顺序,可以得到两个结论:
1.层次遍历的第一个结点一定是根节点;
2.中序遍历中不管是左子树还是右子树,当前根(当前结点)一定是找中序遍历(L1,R1)的结点在层次遍历中最靠前的位置(至关重要!!!).。
啰嗦两句第2点 :(把中序遍历理解成s1、层次遍历理解成s2,那么当前结点就是指s1中谁在s2中最先出现!你会觉得有点傻逼,那肯定是s2中的第一个结点,没错,一开始的时候就是第一个结点,它是整棵树的根节点.但是,下次递归的时候,就不一定是s2中最左边的结点了,为什么呢?因为s2中最左边的结点可能在s1的右子树上.理解不了的可以看我写的案例(上面的图片(案例1中B结点下的左孩子不是C而是D,不就说明了这一点吗?)))。
于是乎,有了下面这个AC代码:
#include<bits/stdc++.h>
using namespace std;
string between, cengci;
int len_cengci, flag[1005];
void dg(int l1, int r1){
int pos, j;
for(j = 0; j<len_cengci; j++){//层次遍历最靠前结点是否在l1到r1的范围,就是当前的根
if(flag[j] == 0){
for(int k=l1; k<=r1; k++){
if(cengci[j] == between[k]){//找到根,并标记为1,退出循环
pos = between.find(cengci[j]);
flag[j] = 1;
break;
}
}
if(flag[j])//退出层次遍历
break;
}
}
cout << between[pos];//根
if(pos > l1) dg(l1, pos-1);//递归左子树
if(pos < r1) dg(pos+1, r1);//递归右子树
}
int main(){
cin >> between >> cengci;
len_cengci = cengci.size();
dg(0, between.size()-1);
return 0;
}
【优化“踏浪而来”】因为每个字符都是唯一的,于是乎,发现结论2可以优化,要找中序遍历(L1,R1)的结点在层次遍历中最靠前的位置,是不是可以提前记录中序遍历中每个结点在层次遍历中出现的位置,(因为两个串的结点是一样的)所以就是在层次遍历中记录每个结点的下标(是不是很神奇) 。
for(int i=0; i<len_cengci; i++){//在层次遍历中记录每个结点的下标
flag[cengci[i]] = i;
}
然后下面开始上AC代码
#include<bits/stdc++.h>
using namespace std;
string between, cengci;
int len_cengci, flag[1005];
void dg(int l1, int r1){
int pos, min = 0x3f3f3f3f;
for(int k=l1; k<=r1; k++){//l1到r1范围出现在层次遍历中最靠前的结点,就是当前根(当前结点)
if(flag[between[k]-'A'+ 1] < min){//找到根,并标记为1,退出循环
min = flag[between[k]-'A'+1];
pos = k;
}
}
cout << between[pos];//根
if(pos > l1) dg(l1, pos-1);//递归左子树
if(pos < r1) dg(pos+1, r1);//递归右子树
}
int main(){
cin >> between >> cengci;
len_cengci = cengci.size();
for(int i=0; i<len_cengci; i++){//在层次遍历中记录每个结点的下标
flag[cengci[i]-'A'+1] = i;
}
dg(0, between.size()-1);
return 0;
}
欢迎点赞和评论