【算法模板】二叉树的三种遍历方式,以及根据两种遍历方式建树

本文详细介绍了二叉树的三种遍历方式,并通过先序遍历与中序遍历,后序遍历与中序遍历组合,实现二叉树的唯一重建。提供了完整的C++代码实现,包括建树过程和遍历结果输出,适用于PAT考试备考及二叉树相关知识的学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:今年九月份的PAT考试就栽在这“两种遍历建树”上了,刚好没看,刚好考到。作为自己的遗憾,今日码完,贴在这里留个纪念,希望能给自己警醒与警钟。

简要概括:

1、二叉树的三种遍历方式分别是 先序(先根)遍历PreOrder,中序(中根)遍历InOrder,后序(后根)遍历PostOrder  。它们的递归写法相当简单,唯一要注意的是,递归的终止条件别忘了写; 至于非递归写法,写法比较麻烦,但是不会爆栈,先不写了。

2、如果已经知道二叉树的 PreOrder + InOrder ,或者是 PostOrder + InOrder ,就可以唯一确定出二叉树的样子并加以建树。建树的要点,以 PreOrder + InOrder 为例:先序遍历可以反映根的位置(首个即为根),中根遍历可以反映左右子树的范围,那么递归下去——由先序遍历确定根字符,在中序遍历中确定根字符位置,则根字符左侧为左子树,右侧为右子树,递归区间即可。

接下来代码为,输入两种遍历,程序会先进行建树,再通过遍历的方式,输出遍历的结果。观察遍历与输入的结果,可以得到程序的建树以及遍历算法,皆为正确。

#include<bits/stdc++.h>
using namespace std;
#define inf 999
char A[inf],B[inf];//A是PreOrder或者是PostOrder,B是InOrder
int n;

struct Node//节点
{
    char c;
    Node *left,*right;
    Node(char t)
    {
        c=t;
    }
};
void Input()//输入两种遍历方式,后序遍历后输入
{
    scanf("%s%s",A,B);
}

//l1,r1是A的区间;l2,r2是B的区间
Node* PreInCreate(int l1,int r1,int l2,int r2)//根据先序以及中序遍历建树
{
    if(l2>r2)return NULL;//要根据中序序列l1,r2而不是l1,r1,来判断是否有无左右子树
    Node *root=new Node(A[l1]);//确定当前的根,必然是先序序列的下一个字符
    int i;
    for(i=l2;B[i]!=A[l1];i++);//确定根在中序序列位置
    int llen=i-l2;//计算左子树的长度
    root->left=PreInCreate(l1+1,l1+llen,l2,i-1);//左子树
    root->right=PreInCreate(l1+llen+1,r1,i+1,r2);//右子树
    return root;//别忘记返回节点
}

/*教科书上写法的先序和中序转树,也是正确的
//l1,r1是A的区间;l2,r2是B的区间,
Node* PreInCreate(int l1,int r1,int l2,int r2)
{
    Node *root=new Node(A[l1]);
    int i;
    for(i=l2;B[i]!=A[l1];i++);//要根据中序序列l1,r2而不是l1,r1,来判断是否有无左右子树
    int llen=i-l2;//计算左子树的长度
    int rlen=r2-i;//计算右子树的长度
    if(llen)//左子树
        root->left=PreInCreate(l1+1,l1+llen,l2,i-1);
    else root->left=NULL;  //教科书喜欢把判断放在函数中,我个人喜欢把剪枝和终止放在函数头
    if(rlen)//右子树
        root->right=PreInCreate(l1+llen+1,r1,i+1,r2);
    else root->right=NULL;
    return root;//别忘记返回节点
}
*/

//l1,r1是A的区间;l2,r2是B的区间
Node* PostInCreate(int l1,int r1,int l2,int r2)//根据后序以及中序遍历建树
{
    if(l2>r2)return NULL;//要根据中序序列l1,r2而不是l1,r1,来判断是否有无左右子树
    Node *root=new Node(A[r1]);//确定当前的根,必然是后序序列的最后一个字符
    int i;
    for(i=l2;B[i]!=A[r1];i++);//要根据中序序列l1,r2而不是l1,r1,来判断是否有无左右子树
    int llen=i-l2;//计算左子树的长度
    root->left=PostInCreate(l1,l1+llen-1,l2,i-1);//左子树
    root->right=PostInCreate(l1+llen,r1-1,i+1,r2);//右子树
    return root;//别忘记返回节点
}
void PreTravse(Node *root)//先序遍历,根左右
{
    if(root==NULL)return;
    printf("%c",root->c);//根
    PreTravse(root->left);//左
    PreTravse(root->right);//右
}
void InTravse(Node *root)//中序遍历,左根右
{
    if(root==NULL)return;
    InTravse(root->left);//左
    printf("%c",root->c);//根
    InTravse(root->right);//右
}
void PostTravse(Node *root)//后序遍历,左右根
{
    if(root==NULL)return;
    PostTravse(root->left);//左
    PostTravse(root->right);//右
    printf("%c",root->c);//根
}
int main()
{
    Node *root=NULL;
    Input();
    printf("len :");//长度
    scanf("%d",&n);
    printf("mode :");//0为先序,1为后序
    int tag;
    scanf("%d",&tag);
    printf("\n");
    if(tag==0)
    {
        root=PreInCreate(0,n-1,0,n-1);
        printf("the output is \n");
        PreTravse(root);
        printf("\n");
        InTravse(root);
        printf("\n");
    }
    else
    {
        root=PostInCreate(0,n-1,0,n-1);
        printf("the output is \n");
        PostTravse(root);
        printf("\n");
        InTravse(root);
        printf("\n");
    }
    return 0;
}

测试数据:

先序中序建树:

ABCDEFGHI

BCAEDGHFI

9

0

后序中序建树:

CBEHGIFDA

BCAEDGHFI

9

1

运行效果图:

也希望能给别人带来收获啦~!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值