天梯赛练习:已知后序遍历和中序遍历,输出层序遍历

树的遍历
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:
输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:
在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:
4 1 6 3 5 7 2

解题思路:开两个全局数组存放中序/后序遍历输入。然后递归建树+层序遍历

要点:
1.递归建树判断左右子树是否存在,若存在如何递归,若不存在则子结点赋为NULL
2.层序遍历借助队列

建树代码:

TreeNode* build(int inB,int inE,int postB,int postE){
	//建树 inB、inE分别是中序遍历数组的首尾元素索引;postB、postE则是后序的
	int i = 0;
	TreeNode* newnode =new TreeNode;
	newnode->val = postor[postE];//后序最后一个输入即根节点 
	while(inorder[inB + i] != postor[postE])//找到根节点 
		i++;
	if(i > 0)//左子树存在 
		newnode->lchild = build(inB,inB + i - 1,postB,postB + i -1);//中后左子树长度相等,且位置相同 
	else 
		newnode->lchild = NULL;//即使是空值也必须初始化! 
	if(inB + i < inE)//右子树存在 
		newnode->rchild = build(inB + i + 1,inE,postB + i ,postE - 1);//注意最后一个结点是已经赋给树的根节点,应该刨除 
	else 
		newnode->rchild = NULL;//同上,否则层序遍历无法进行 
	return newnode;
}//build

这里说一下左右子树的存在判定条件以及左右子树如何实现递归建立:

判定条件:
中序遍历中,根节点的左边表示左子树。如果根节点左边还有值,说明左子树存在。i是根节点到中序遍历第一个值(最左边一个值)的距离,当距离i > 0说明中序遍历中当前节点的值并不位于最左边,它的左边还有值,即左子树存在。
同理,中序中根节点的右侧表示右子树。若根节点(inB + i)右边还有值说明右子树存在。是否还有值通过根节点的索引到最后一个数的索引之间是否相等来判断。相等则没有值,小于则还有值(inB+i<inE) 即右子树存在。

递归建立:
如何递归应该是这题的一个难点。
建立左子树:
先考虑中序遍历的两个参数 inB 和 inE:每次递归取根节点(根节点索引为inB + i)的左半部分,也就是[inB,inB + i -1]
然后后序遍历的两个参数postB及postE:每次递归取根节点的左子树部分。那么后序遍历中某个特定的根节点左子树应该怎么确定呢?实际上,这里左子树的元素数跟上面中序的左半部分元素数应该是相等的(因为是同一个根节点的子节点,二者表述的意义相同只是方式顺序不同)并且我们知道,中后序都是先输出左子树。也就是说,只要在后序遍历上截出一个跟中序左子树同样长度的序列(inB+i-1-inB = i-1),就是我们要的部分。这个部分用代码描述:[postB,postB + i - 1]
建立右子树
同样先考虑中序部分:取根节点的右半部分区间 [inB + i + 1,inE]
然后后序遍历的两个参数:由上得,后序遍历的前半部分是左子树[postB,postB + i - 1],而我们知道最后一个元素是根节点(postE)。那么剩下的部分就是右子树。即 [postB +i ,postE - 1] (后序遍历的数组各个部分在二叉树中的分布参照下图:)后序遍历数组结构图示
可以对比着看看 中序遍历数组结构如下中序遍历数组结构图示
层序遍历代码:

void levelorder(TreeNode* T){
	//借助队列,层次遍历
	queue<TreeNode*> q;
	if(T == NULL)
		exit(-1);
	q.push(T);
	TreeNode* front;
	while(!q.empty()){
		front = q.front();
		q.pop();
		if(front->lchild != NULL){//左结点入队 
			q.push(front->lchild);
		}
		if(front->rchild != NULL)//右结点入队 
			q.push(front->rchild);
		if(front->val != T->val)//输出 
			cout<<" ";
		cout<<front->val;
	}
} //levelorder

层序遍历这里主要就是借助队列来完成。详细可以看看这篇博文:https://blog.csdn.net/monster_ii/article/details/82115772
与上文不同的是,本题要求输出末尾不可以有空格。所以空格干脆在每一个数据之前输出,然后特判一下第一个数据(根节点)不输出即可。

完整的AC代码:


#include<bits/stdc++.h>
using namespace std;
typedef struct TreeNode{
	int val;
	struct TreeNode *lchild,*rchild;
}TreeNode;
int inorder[35],postor[35];//因为函数build需要用到,中序后序应该建成全局数组 
TreeNode* build(int inB,int inE,int postB,int postE){
	//建树 
	int i = 0;
	TreeNode* newnode =new TreeNode;
	newnode->val = postor[postE];//后序最后一个输入即根节点 
	while(inorder[inB + i] != postor[postE])//找到根节点 
		i++;
	if(i > 0)//左子树存在 
		newnode->lchild = build(inB,inB + i - 1,postB,postB + i -1);//中后左子树长度相等,且位置相同 
	else 
		newnode->lchild = NULL;//即使是空值也必须初始化! 
	if(inB + i < inE)//右子树存在 
		newnode->rchild = build(inB + i + 1,inE,postB + i ,postE - 1);//注意最后一个结点是已经赋给树的根节点,应该刨除 
	else 
		newnode->rchild = NULL;//同上,否则层序遍历无法进行 
	return newnode;
}//build
void levelorder(TreeNode* T){
	//借助队列,层次遍历
	queue<TreeNode*> q;
	if(T == NULL)
		exit(-1);
	q.push(T);
	TreeNode* front;
	while(!q.empty()){
		front = q.front();
		q.pop();
		if(front->lchild != NULL){//左结点入队 
			q.push(front->lchild);
		}
		if(front->rchild != NULL)//右结点入队 
			q.push(front->rchild);
		if(front->val != T->val)//输出 
			cout<<" ";
		cout<<front->val;
	}
} //levelorder
void DeleteTree(TreeNode * T)
{
    if(T == NULL) return;
    DeleteTree(T->lchild);
    DeleteTree(T->rchild);
    delete T;
}
int main(){
	int n,i;
	cin>>n;
	for(i = 1;i <= n; i++)//输入后序遍历 
		cin>>postor[i];
	for(i = 1;i <= n; i++)//输入中序遍历 
		cin>>inorder[i];
	TreeNode *T = build(1,n,1,n);//建树 
	levelorder(T);//层序遍历 
	DeleteTree(T);
	return 0;
}

建树部分参考自:https://blog.csdn.net/weixin_40163242/article/details/88579989
注意不可直接结合两个博文,应该在第二个连接的基础上加上这个部分:

	if(i > 0)//左子树存在 
		newnode->lchild = build(inB,inB + i - 1,postB,postB + i -1);//中后左子树长度相等,且位置相同 
	else 
		newnode->lchild = NULL;//即使是空值也必须初始化! 
	if(inB + i < inE)//右子树存在 
		newnode->rchild = build(inB + i + 1,inE,postB + i ,postE - 1);//注意最后一个结点是已经赋给树的根节点,应该刨除 
	else 
		newnode->rchild = NULL;//同上,否则层序遍历无法进行 

因为第二篇博文使用的层序遍历稍微复杂一些(使用了vector),好像不需要左右子节点为空的时候置NULL(这个bug老是段溢出找了我三个点。。。我太难了┭┮﹏┭┮)

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值