利用前序和后序序列构建真二叉树
一般来讲,给定二叉树的先序遍历序列和后序遍历序列,不能唯一确定这棵二叉树。但 是,对于真
二叉树来讲,给定它的先序遍历序列 pre 和后序遍历序列 post,可以唯一确定这 棵真二叉树。所谓真
二叉树是指每个内部节点都有两个孩子的二叉树。
根据真二叉树的先序遍历序列 pre 和后序遍历序列 post,编写一个实现真二叉树的构造 及中序遍
历的程序,要求如下:
(1)具有操作界面;
(2)可以测试多组数据,每组数据的真二叉树先序遍历序列 pre、后序遍历序列 post 通过键盘输
入
( 3 ) 将 先 序 遍 历 序 列 pre 、 后 序 遍 历 序 列 post 、 中 序 遍 历 序 列 in 保 存 到 文 本 文 件
proper-bitree.txt 中, 格式如下:
真二叉树的先序遍历序列 pre
真二叉树的后序遍历序列 post
真二叉树的中序遍历序列 in
分析:二叉树前序遍历的第一个元素和后序遍历的最后一个元素为树根,后序遍历序列的倒数第二个元素为右子树的根,前序遍历中右子树的根的前面的元素均为左子树元素,从而分隔左右子树的元素,据此可以采用递归依次构建每一棵子树。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct BitNode
{
char data;
struct BitNode *lchild;
struct BitNode *rchild;
} BitNode;
BitNode *Creat_ProperBiTree(char *pre, char *post, int length, int *tag); //前序后序转中序
void InOrderTraverse(BitNode*T);
int main(void)
{
int c;
while(1)
{
printf("请开始选择:0、构造真二叉树,1、退出\n");
scanf("%d", &c);
fflush(stdin);
switch(c)
{
case 0:
{
FILE *fp ;
int tag = 0;//标记错误,0为无错误
if((fp = fopen("proper-bitree.txt", "a")) == NULL)
{
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
system("cls");
char pre[1024];
char post[1024];
//文件写入前序序列
printf("请输入前序输出序列(不要有空格)\n");
gets(pre);
fputs(pre, fp);
fprintf(fp, "\n");
//文件写入后序序列
printf("请输入后序输出序列(不要有空格)\n");
gets(post);
fputs(post, fp);
fprintf(fp, "\n");
fclose(fp);
int prelength = strlen(pre);
int postlength = strlen(post);
if(prelength != postlength || prelength % 2 == 0 || postlength % 2 == 0)
{
tag = 1;//长度不符合要求,设置错误
}
//开始构造真二叉树
BitNode* T;
T = Creat_ProperBiTree(pre, post, prelength, &tag);//tag指示是否出错
if(tag == 0)
{
InOrderTraverse(T);
if((fp = fopen("proper-bitree.txt", "a")) == NULL)
{
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
fprintf(fp, "\n");//行末增加换行
fclose(fp);
printf("结果已写入文件\n");
}
else
{
if((fp = fopen("proper-bitree.txt", "a")) == NULL)
{
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
fprintf(fp, "对不起,输入的序列无法构成真二叉树\n");
fclose(fp);
printf("结果已写入文件\n");
}
system("pause");
}
break;
case 1:
{
return 0;
break;
}
default:
printf("输入错误,请重新输入\n");
break;
}
}
return 0;
}
void InOrderTraverse(BitNode*T)
{
if(T)
{
InOrderTraverse(T->lchild);
//在文件中写入中序遍历序列
FILE *fp1;
if((fp1 = fopen("proper-bitree.txt", "a")) == NULL)
{
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
fputc(T->data, fp1);
fclose(fp1);
InOrderTraverse(T->rchild);
}
}
BitNode *Creat_ProperBiTree(char *pre, char *post, int length, int *tag) //前序后序转中序
{
if(length == 1)//有一个节点,必为根
{
BitNode* T = (BitNode*)malloc(sizeof(BitNode));
if(pre[0] == post[0])//唯一的节点相同
{
T->data = pre[0];
T->lchild = NULL;
T->rchild = NULL;
return T;
}
else//唯一的节点不相同,必错误
{
*tag = 1;
return NULL;
}
}
if(length % 2 == 0)//序列长度为偶数,无法构成真二叉树
{
*tag = 1;
return NULL;
}
int i = 0;
if(pre[0] != post[length - 1])//在前序和后序遍历序列中找到的根不一样
{
*tag = 1;//设置错误
return NULL;
}
char Root = pre[0];//根
char rightRoot = post[length - 2]; //右子树根
while(pre[i] != rightRoot && i < length)
{
i++;//在前序遍历中找到右子树的根,从而分隔左右子树
}
if( i == length )
{
*tag = 1;//在前序序列没找到右子树的根,错误
return NULL;
}
int leftlength = i - 1;//左子树节点个数
int rightlength = length - i;//右子树节点个数
BitNode * T = (BitNode*)malloc(sizeof(BitNode));
T->data = Root;
T->lchild = Creat_ProperBiTree(&pre[1], &post[0], leftlength,tag);
T->rchild = Creat_ProperBiTree(&pre[i], &post[i - 1], rightlength,tag);
return T;
}
注:文件指针做成全局变量更好,会节省不少行代码,也可以提高代码运行效率。(懒得不想改了)
附上流程图: