C,核心代码有详细注释,自写,请读者视情参考
思想:
根据中序排序的特点我们可以知道,如果我们选中其中某一节点,它的左边一定是这个节点的左子树,右边一定是这个节点的右子树。
根据先序排序的特点我们可以知道,如果我们选中其中某一节点,它右边的节点一定是先排列完左子树,再排列右子树。
那么我们能否根据这两个规律,确定唯一的二叉树?
如果确定能够构造唯一的二叉树,那么根据后序遍历的算法很容易得出后序序列。
所需知识:
C,二叉树,先序遍历,中序遍历,后序遍历
途径:
采用分治思想,先分后合。将左子树和右子树逐层分开,直到左边没有节点,右边没有节点,此时该节点为叶子节点,再进行合并,接上上一层的节点。分治法一般采用递归实现拆分和合并,所以这里用一个递归函数来实现。
举例:
(建议直接看代码,不清楚再看这里)
对于示例先序pre[] = abcde,中序in[] = bcade,从先序第一个节点a开始,在中序中找到a,则a的左子树为preL[] = bc(这里可以看出左子树是两个节点),右子树为preR[] = de(两个)。
那么,我们可以知道先序中a的后面两个节点是左子树inL[] = bc,再后面两个是右子树inR[] = de。把左子树接上a,右子树接上a(因为是递归,所以会从底层一个一个接上的)。
对左子树再进行拆分,先序preL[] = bc,中序inL[] = bc,从先序第一个节点b开始,在中序中找到b,则b的左子树为 (这里可以看出该节点没有左子树),右子树为c(一个)。
那么,我们可以知道先序中b的后面零个节点是左子树,再后面一个是右子树。再对右子树进行拆分,发现右子树只有一个,已经是叶子了,那么接上上一层。
右子树同样道理,拆分到底层叶子不可再拆分,再从底层一层一层接上去。
.
当然,若是对后序比较熟悉的话,就会发现,这接上去的顺序其实就是后序的顺序,针对这道题目可以直接输出。
所以这道题有更简单的写法,简单写法代码贴在最后以供参考,但这道题目的是理解三种序列的特点,熟练的读者可以尝试自行修改。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(disable:4996)
#define ElemType char
#define OK 1
#define ERROR 0
#define MaxNodeCount 50
typedef int Status;
typedef struct BiTreeNode
{
ElemType data;
struct BiTreeNode *lchild;
struct BiTreeNode *rchild;
}BiTreeNode, *Bitree;
Bitree Stack[MaxNodeCount];//栈
int base = 0, top = 0;
char pre[100];//先序
char in[100];//后序
//根据给出前序和中序序列,创建二叉树。
//preL:前序左界,preR前序右界,inL中序左界,inR中序右界
//返回:当前构造子树根节点
Bitree PreInCreat(int preL, int preR, int inL, int inR) {
Bitree root;
root = (BiTreeNode *)malloc(sizeof(BiTreeNode));//建立子树的根节点
root->data = pre[preL];//节点对应的数值
int i;
for (i = inL; in[i] != root->data; i++);//在中序中找到这个数值的位置
int lLen = i - inL;//计算左子树的长度
int rLen = inR - i;//计算右子树的长度
if (lLen)//若左树非空,再构造左子树
{
root->lchild = PreInCreat(preL + 1, preL + lLen, inL, inL + lLen - 1);
//请自行画数轴确定要传入的左界和右界
}
else root->lchild = NULL;//若左树为空,接上空节点
if (rLen)
{
root->rchild = PreInCreat(preR - rLen + 1, preR, inR - rLen + 1, inR);
}
else root->rchild = NULL;
return root;
}
//后序非递归遍历,详情请看《二叉树后序非递归遍历》
Status PostOrder(Bitree &T, Status(*Visit)(Bitree &)) {
if (T == NULL)
{
return ERROR;
}
Bitree p = T, r = NULL;
base = 0; top = 0;
while (p || base != top) {
if (p) {
Stack[top++] = p;
p = p->lchild;
}
else {
p = Stack[top - 1];
if (p->rchild&&r != p->rchild) {
p = p->rchild;
}
else {
p = Stack[--top];
if (!Visit(p))return OK;
r = p;
p = NULL;
}
}
}
}
Status PrintData(Bitree &T) {
printf("%c", T->data);
return OK;
}
Status DoNothing(Bitree &T) {
return OK;
}
Status main() {
scanf("%s", pre);
scanf("%s", in);
Bitree T = PreInCreat(0, strlen(pre)-1, 0, strlen(in)-1);//注意输入的左右界
PostOrder(T, PrintData);
}
Description
二叉树的三种遍历都可以通过递归实现。
如果我们知道一棵二叉树的先序和中序序列,可以用递归的方法求后序遍历序列。
输入格式
两行,第一行一个字符串,表示树的先序遍历,第二行一个字符串,表示树的中序遍历。树的结点一律用小写字母表示。
输出格式
一个字符串,树的后序序列。
输入样例
abcde
bcade
输出样例
cbeda
c版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(disable:4996)
#define ElemType char
#define OK 1
#define ERROR 0
#define MaxNodeCount 50
typedef int Status;
char pre[100];//前序
char in[100];//中序
void PreInCreat(int preL, int preR, int inL, int inR) {
char data = pre[preL];
int i;
for (i = inL; in[i] != data; i++);//在中序中找到对应的前序位置
int lLen = i - inL;//左子树的大小
int rLen = inR - i;//右子树的大小
if (lLen)//如果有左子树,则继续划分
PreInCreat(preL + 1, preL + lLen, inL, i - 1);
if (rLen)//如果有右子树,则继续划分
PreInCreat(preR - rLen + 1, preR, i + 1, inR);
printf("%c", data);//如果是叶子,则输出
}
Status main() {
scanf("%s", &pre);
scanf("%s", &in);
PreInCreat(0, strlen(pre) - 1, 0, strlen(in) - 1);
}
c++版本
#include <iostream>
#include <cstring>
using namespace std;
char pre[128];
char in[128];
void PrintByPost(int inl, int inr, int prel, int prer) {
char c = pre[prel];
int i;
for (i = 0; in[i] != c; i++);
if (i - inl)PrintByPost(inl, i - 1, prel + 1, prel + i - inl);
if (inr - i)PrintByPost(i + 1, inr, prel + i - inl + 1, prer);
cout << c;
}
int main() {
cin >> pre >> in;
PrintByPost(0, strlen(in) - 1, 0, strlen(pre) - 1);
}
这篇博客探讨如何根据先序和中序遍历序列构建二叉树,并导出后序遍历序列。通过分治思想,使用递归方法拆分和合并二叉树节点,最终实现从给定序列构造唯一二叉树并输出后序遍历顺序。示例展示了具体的操作过程和C语言实现。
1776

被折叠的 条评论
为什么被折叠?



