先序遍历中序遍历还原二叉树

前言:这算是在刷树题的第一篇blog,记录一下,方便以后复习

准备

  • 先序遍历二叉树结果的第一个节点是根节点
  • 中序遍历二叉树结果中左子树右子树又以根节点隔开

假定:
先序遍历结果为: A B D F G H I E C
中序遍历结果为: F D H G I B E A C

第一次考虑

毫无疑问通过先序遍历可以知道A是最开始的根节点,所以中序遍历中我们可以知道它的结构是这样的
在这里插入图片描述
再进一步对上图中的左子树进行考虑,现在就变成了
先序遍历结果B D F G H I E
中序遍历结果F D H G I B E
在这里我们先求出来新的先序遍历结果在原来先序遍历结果中的位置
如图
在这里插入图片描述

  • i表示先序遍历结果的初始位置,j表示末尾
  • k表示中序遍历结果的初始位置,H表示末尾
  • m标识中序结果中的根节点
    我们先看左子树的先序遍历结果位置
    我们可以看到先序遍历结果中B-E是分离后的左子树先序遍历结果,B的位置很好求就是i+1,
    E的位置我们不妨设x,则有上下对齐m-k=x-i,得x=m-k+i
    所以这次分离后的先序结果位置范围是[i+1,m-k+i]
    再看左子树的中序遍历位置
    我们可以看到上图中序遍历结果中F-E是分离后的左子树中序遍历结果,我们也可以通过设x的方式来求,得这次分离后的中序结果位置范围是[k,m-1]
    接下来再看右子树的先序遍历结果位置
    同样是设x,最后范围是[m+j-h+1,j]
    右子树的中序遍历结果位置
    [m+1,H]

第二次考虑

同理,由先序可知B为根节点,再去中序遍历结果中以B分离左子树FDHGI,右子树E,就变成了下图
在这里插入图片描述
再往下我就不列了,这样我们就可以还原二叉树,如果想要输出后序结果,直接后序遍历就行,如果需要求二叉树的高度,直接求就行

好了,道理懂了,我们就上代码叭

首先是二叉树结构定义

typedef struct bitnode
{
    struct bitnode *lchild;
    struct bitnode *rchild;
    char data;
} BiTNode,*BiTree;

无论是树结构的定义还是先序后序遍历什么的,要想方便递归是离不开的

下面就是还原树的递归,其实就是对我们刚才原理方面的一个模拟

//两个string分别表示先序中序结果集的传参
void houzhong(string xianxu,int i,int j,string zhongxu,int k,int h,BiTree *t)
{
    //m用于标志中序结果集里的根节点
    int m;

    //申请节点
    *t =(BiTree)malloc(sizeof(BiTNode));

    //将根节点的值给这个新节点
    (*t)->data=xianxu[i];
    //让m从中序结果集的第一个位置开始遍历,从而找到中序结果集中的那个根节点的位置
    m=k;
    while(zhongxu[m]!=xianxu[i])
        m++;

    //如果中序的第一个就是根节点,那说明还原后的左子树是空的
    if(m==k)
        (*t)->lchild=NULL;
    else
        houzhong(xianxu,i+1,m-k+i,zhongxu,k,m-1,&(*t)->lchild);

    //如果中序的最后一个是根节点,那说明还原后的右子树是空的
    if(m==h)
        (*t)->rchild=NULL;
    else
        houzhong(xianxu,m+j-h+1,j,zhongxu,m+1,h,&((*t)->rchild));

}

我们怎么知道还原的成功与否呢
利用先序遍历一下还原好的这棵二叉树就好了,看看跟原来一样不

//用于测试是否还原成功的先序遍历方法
void preorder(BiTree bt  )
{
    if(bt ==NULL) return;
    else
    {
        printf(" %c",bt->data);
        preorder(bt->lchild);
        preorder((bt->rchild));
    }
}

运行一下
在这里插入图片描述
分别输入了先序中序,还原之后进行先序遍历,结果与输入的先序是一样的。

整体的一个代码是这样的:

#include <stdio.h>
#include <stdlib.h>
#include <bits/stdc++.h>
#define MAX 30
using namespace std;
//定义树的递归结构
typedef struct bitnode
{
    struct bitnode *lchild;
    struct bitnode *rchild;
    char data;
} BiTNode,*BiTree;
/*
    xianxu:先序遍历的结果
    i:先序的起点
    j:先序的终点
    zhongxu:中序遍历的结果
    k:中序的起点
    h:中序的终点
    BiTree:二叉树
*/
//递归的使用
void houzhong(string xianxu,int i,int j,string zhongxu,int k,int h,BiTree *t)
{
    //m用于标志中序结果集里的根节点
    int m;

    //申请节点
    *t =(BiTree)malloc(sizeof(BiTNode));

    //将根节点的值给这个新节点
    (*t)->data=xianxu[i];
    //让m从中序结果集的第一个位置开始遍历,从而找到中序结果集中的那个根节点的位置
    m=k;
    while(zhongxu[m]!=xianxu[i])
        m++;

    //如果中序的第一个就是根节点,那说明还原后的左子树是空的
    if(m==k)
        (*t)->lchild=NULL;
    else
        houzhong(xianxu,i+1,m-k+i,zhongxu,k,m-1,&(*t)->lchild);

    //如果中序的最后一个是根节点,那说明还原后的右子树是空的
    if(m==h)
        (*t)->rchild=NULL;
    else
        houzhong(xianxu,m+j-h+1,j,zhongxu,m+1,h,&((*t)->rchild));

}
//还原二叉树的方法
BiTree ReBiTree(string houxu,string zhongxu,int n)
{
    BiTree root;
    if(n<=0)
        root=NULL;
    else
    //最开始初始位置就是0,末尾位置就是n-1
        houzhong(houxu,0,n-1,zhongxu,0,n-1,&root);
    return root;

}
//用于测试是否还原成功的先序遍历方法
void preorder(BiTree bt  )
{
    if(bt ==NULL) return;
    else
    {
        printf(" %c",bt->data);
        preorder(bt->lchild);
        preorder((bt->rchild));
    }
}


int main()
{
    //定义一个空树
    BiTree T;
    int n;
    string  xianxu="";
    string zhongxu="";
    T = NULL;
    cin>>n;
    cin>>xianxu;
    cin>>zhongxu;
    T=ReBiTree(xianxu,zhongxu,n);
    preorder(T);
    return 0;
}

如果要输出后序二叉树:

void postorder(BiTree bt  )
{
    if(bt ==NULL) return;
    else
    {
        preorder(bt->lchild);
        preorder((bt->rchild));
        printf(" %c",bt->data);
    }
}
  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值