前言:今年九月份的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
运行效果图:
也希望能给别人带来收获啦~!