二叉树之前中后序之知二求一

  • 今天学习了二叉树,也是做了题才更深入的熟悉了一下啊
  • 好 直接来说说我们的题目
  1. 已知前序和中序,叫你求后序
  • 例如:前序ABCD,中序BADC  求出后序为:BDCA
  • 样例:
  • 输入:
  • EACBDGF
  • ABCDEFG
  • 输出:
  • BDCAFGE
  • 这东东,我今天也是研究了好久 去理解了好久才理解会的
  • 如果理解了前中后序的原理,应该是不难的。
  • 前序遍历是先打印再递归左和右,例如样例前序中第一个E是根结点,接下来去中序中遍历,找到E,那么左边的那部分就是左子树的结点,E右边的部分就是右子树的结点。 
  •  我的思路是后序的部分是入栈顺序是最后一个元素入栈到第一个元素,然后依照栈先进后出的原理,最后读的时候可以读顶部,再删除顶部的元素,直到栈为空。最后说说递归的部分,也是整个代码最难理解的部分,,,可以看到样例中从后往前看,先是根节点,然后是中序中在E的右边那部分,最后才是中序中在E的左边那部分。所以等下写递归的时候要先判断右边,再判断左边。再判断是否为空,如果不为空,就用递归。
  • 这里有一个问题,就是在中序和前序中的位置对不好,以样例为例,当进栈E之后,中序的ABCD位于0,1,2,3的位置(位置用0--6表示),而前序在1、2,3,4位置,这怎么办呢?
    其实,通过观察,我们会发现,一个位置,每被划分为左半部分一次,中序和前序的位置就会错开1。 那么,了解了这点以后,就不会有什么大问题了
  • 这样说可能听不懂,看下代码把,然后按照代码在纸上推一遍,肯定会懂的。
#include<bits/stdc++.h>
using namespace std;

string qian,zhong;

stack<char>hou; 

void tree(int left,int right,int s) //left为左边界,right为右边界,s为被划分为左半部分的次数
{
	hou.push(qian[left+s]); //由于会错开s,所以要加上s
	for(int i = left;i<=right;i++)
	{
		if(zhong[i]==qian[left+s])  //找到输出的点
		{
			if(i!=right) tree(i+1,right,s); //如果是right,那么右边的就不用做了,下面同理
			if(i!=left) tree(left,i-1,s+1);
		}
	}
	return;
}

int main()
{
	cin>>qian>>zhong;
	int len = qian.size();
	tree(0,len-1,0);
	while(!hou.empty())
	{
		cout<<hou.top(); //读出栈顶
		hou.pop();  //出栈
	}
	return 0;
}

2 、接下来是 已知中序,后序,求前序

  • 其实就是跟上面那个差不多,反过来推
  • 题目描述

    给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度≤8)。

    输入格式

    2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。

    输出格式

    1行,表示一棵二叉树的先序。

    输入输出样例

    输入

    BADC
    BDCA
    

    输出 

    ABCD
    道理是一样的,

    具体步骤如下:

  • 输出该部分后序遍历最后一项(后序遍历是左右根,所以最后一项是根)
  • 在中序遍历中找到他
  • 分成左右两部分
  • 判断是否为空
  • 如果不为空,回到第1步
  • 在这里,中序和后序中的位置也是对不好,以样例为例,当输出A和B之后,中序的DC位于2、3的位置(位置用0--3表示),而后序在1、2位置。
    这里,一个位置,每被划分为右半部分一次,中序和后序的位置就会错开1。还是以样例为例,DC在有且仅有第一次划分是被分到右边,所以中序和后序的位置会错开1个点。
  • 代码:
#include<bits/stdc++.h>
using namespace std;

string zhong,hou;

void tree(int left,int right,int s) //left,right分别为左右边界,s是被划分为右半部分的次数
{
	if(left>right||s>right) /这个貌似没什么用
		return;
	cout<<hou[right-s]; //因为会错开s所以要减s
	for(int i = left;i<=right;i++)
	{
		if(zhong[i] == hou[right-s]) /找出输出的点
		{
			if(i!=left) tree(left,i-1,s); //如果是left,那么左边就不会有结点了,就不会进行了,下面同理
			if(i!=right) tree(i+1,right,s+1);
			break;
		}
	}
	return;
}
int main()
{
	cin>>zhong>>hou;
	int len = zhong.size();
	tree(0,len-1,0);
	return 0;
}
  • 最后一种是已知前序,后序  这种情况下,中序是不明确的,有多种结果的。
  • 例如:(自己画的别嫌弃)

  •  我们可以确定的是根结点是A,但是我们无法知道,哪个结点时左子树,哪个结点时右子树,于是就有了上面图片的四种可能。
  • 但是我们可以计算出中序有多少种情况:
  • 例如题目:
  • 输入格式

    输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。

    输出格式

    输出可能的中序遍历序列的总数,结果不超过长整型数。

    输入输出样例

    输入 

    abc                           
    cba
    

    输出

    4
  • 在一颗树上若有一个结点是只有一个子结点,那么这个子结点在左在右都不影响先序后序的遍历顺序,那么总树数就要✖2 (因为它有两种选择,一种是变成左子树,一种是变成右子树),所以问题变成了找到子结点。
  • 我们试几个例子,可以发现,以样例为例,在前序遍历中某一元素A的的后继元素是B,且在后序遍历中A的前驱元素也是B,那么A就只有一个子树,总树数就要✖2。代码:
  • #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
    	char a[1000]="",b[1000]="";
    	cin>>a>>b;
    	int n = strlen(a);
    	int num = 1;
    	for(int i = 0;i<=n-2;i++)
    	{
    		for(int j = 0;j<=n-1;j++)
    		{
    			if(a[i]==b[j]&&b[j-1]==a[i+1]) //找到只有唯一子树的子结点
    				num*=2;
    		}
    	}
    	cout<<num<<endl;
    }

    晚安

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烂尾歌·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值