算法训练 求先序排列(递归 ,蓝桥杯C++,简洁算法、代码)

算法训练 求先序排列

资源限制
时间限制: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;
}

后语:这道题看了大佬的文章思路顿开,自己也继续推导出了给先中序求后序的代码,今天收获满满,如果文章有待商榷,还希望大家多多批评指正!

猜你喜欢

转载自blog.csdn.net/Kyrie_irving_kun/article/details/113705519
今日推荐