写完NOJ后看了一眼csdn,发现并没有人把算法的分析过程发出来。我使用的算法参考的是书上的第179页给出的算法流程,发出来供大家交流讨论。
首先题目给出我们一个前序序列和一个中序序列,要求输出后序序列。第一想法便是通过前序序列和中序序列建立一个二叉树,再通过后序遍历输出。那么,我们如何通过前序和中序确定一个二叉树呢?我们先明确前序和中序的特点。前序的访问顺序是根-左结点-右结点,中序则是左结点-根-右结点。我们可以发现前序中第一个结点一定是根结点。
OK,算法的设计思路来了,用一下分治的思想,我们可以找到前序的第一个结点,然后以此将中序序列分成左右子树,将左右子树的序列分别传给我们的创建二叉树的函数,反复如此(相信经过前三题的历练,大伙对递归已经有了一定的理解,这里递归部分直接贴代码),注意,前序序列只需要用同一个就行,你需要做的就是在当前中序的序列中,找到其中出现的第一个对应的前序序列中的结点,即可。是不是已经有思路了?可以尝试自己动手实践了!
老规矩,结尾贴上AC的源码并附上NOJ的测试样例,方便大伙调试。祝诸君学业有成,希望大伙可以点赞支持,抱拳。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* NOJ_18.c,建立二叉树的二叉链表
* 由一个二叉树的前序序列和中序序列,输出后序序列
* 编译:gcc NOJ_18.c -o NOJ_18.exe
* 运行:./NOJ_18.exe
* 输入:分两行分别输入一颗二叉树的前序和中序序列
* 输出:输出该二叉树的后序序列
*
* author:Aimer
* date: 2023-05-11
*/
//定义数据域类型
typedef char ElemType;
//定义二叉树节点
typedef struct BinTreeNode
{
ElemType data; //数据域
struct BinTreeNode * left; //左节点
struct BinTreeNode * right; //右节点
}BinTreeNode,*PBinTreeNode;
//函数声明
void createBinTree(PBinTreeNode,char*,char*);//创捷二叉树
void postOrderOutput(PBinTreeNode); //后序输出
//程序入口
int main(int argc,char* argv[])
{
char str_pre[1000] = {0};
char str_in[1000] = {0};
scanf("%s",str_pre);
scanf("%s",str_in);
PBinTreeNode root = (PBinTreeNode)malloc(sizeof(BinTreeNode));
createBinTree(root,str_pre,str_in);
postOrderOutput(root);
free(root);
return 0;
}
/* 创建二叉树
* node,一个二叉树节点指针,str_pre该树的前序序列,str_in中序
* 通过前序确定节点,再中序中分割
* 通过递归方式创建
*/
void createBinTree(PBinTreeNode node,char* str_pre,char* str_in)
{
int i = 0,j=0,len = strlen(str_in);
while(str_pre[j] != str_in[i])
{
if(i == strlen(str_in))
{
j++,i=0;
continue;
}
i++;
}
node->data = str_pre[j];
if(i==0)//如果没有左节点
node->left = NULL;
if(i==strlen(str_in)-1)
node->right = NULL;
if(i>0)
{
node->left = (PBinTreeNode)malloc(sizeof(BinTreeNode));
char* str_left = (char*)malloc(sizeof(char)*(i+1));//多开一个空间用于填放'\0'
for(int k=0;k<i;k++)
{
str_left[k] = str_in[k];
}
str_left[i] = 0;
createBinTree(node->left,str_pre,str_left);
}
if(i<strlen(str_in)-1)
{
node->right = (PBinTreeNode)malloc(sizeof(BinTreeNode));
char* str_right = (char*)malloc(sizeof(char) * (len - i)); //存放右子树序列
for(int k=0;k<len-i-1;k++)
{
str_right[k] = str_in[k+i+1];
}
str_right[len-i-1] = '\0';
createBinTree(node->right,str_pre,str_right);
}
}
/* 后序输出
* ptr_node,一个二叉树结节点指针
* 通过后序方式递归输出
*/
void postOrderOutput(PBinTreeNode ptr_node){
//后序遍历一棵二叉树
if(ptr_node->left){
postOrderOutput(ptr_node->left);
}
if(ptr_node->right){
postOrderOutput(ptr_node->right);
}
printf("%c",ptr_node->data);
}
/*
测试样例
ABDFGCEH
BFDGACEH
*/