1364:二叉树遍历(flist)(树的经典题)

【题目描述】
树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。

假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,求该树的先序遍历字符串。

【输入】
两行,每行是由字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的中序遍历和按层遍历的序列。

【输出】
一行,表示二叉树的先序序列。

【输入样例】
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;
}

欢迎点赞和评论

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值