PreOrder: GDAFEMHZ
InOrder: ADEFGHMZ
我们如何还原这颗二叉树,并求出他的后序遍历?
我们基于一个事实:中序遍历一定是 { 左子树中的节点集合 },root,{ 右子树中的节点集合 },前序遍历的作用就是找到每颗子树的root位置。
算法1
输入:前序遍历,中序遍历
1、寻找树的root,前序遍历的第一节点G就是root。
2、观察前序遍历GDAFEMHZ,知道了G是root,剩下的节点必然在root的左或右子树中的节点。
3、观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树中的节点,G右侧的HMZ必然是root的右子树中的节点,root不在中序遍历的末尾或开始就说明根节点的两颗子树都不为空。
4、观察左子树ADEF,按照前序遍历的顺序来排序为DAFE,因此左子树的根节点为D,并且A是左子树的左子树中的节点,EF是左子树的右子树中的节点。
5、同样的道理,观察右子树节点HMZ,前序为MHZ,因此右子树的根节点为M,左子节点H,右子节点Z。
观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了:
从而得到PostOrder: AEFDHZMG
改进:
更进一步说,其实,如果仅仅要求写后续遍历,甚至不要专门占用空间保存还原后的树。只需要用一个数组保存将要得到的后序,就能实现:
算法2
输入:一个保存后序的数组,前序遍历,中序遍历
1、确定根,放在数组末尾
2、确定左子树的索引范围,放在数组中相同索引的位置。
3、确定右子树索引范围,放在数组中对应索引的位置,刚好能放下。
4、用左子树的前序遍历和中序遍历,把后序遍历保存在对应索引的位置
5、用左子树的前序遍历和中序遍历,把后序遍历保存在对应索引的位置
引申问题
同样我们可以用中序遍历和后序遍历还原这颗树。
然而,如果是前序遍历和后序遍历,就不能够还原这棵树了,因为无法找到中间点,注意下面这两种情况:
两棵树的前序是相同的,两棵树的后序也是相同的。换句话说,如果有一颗子树,它的根节点的一个子树是空树,那么就无法判定那一个子树是空树。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以上是转载内容
下面是自己写的代码:
用二叉树的先序序列和中序序列来还原该二叉树:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct BI{
char ch;
BI*lchild;
BI*rchild;
};
typedef struct BI BiTree;
申明:
void Pre_In_Build(int& ,int,int,BiTree*&); //用先序序列和中序序列来实现还原二叉树(选做的)
void Destroy_Tree(BiTree*&); //销毁该二叉树
char Preorder[100],Inorder[100]; //存储输入的先序序列和中序序列
int main()
{
BiTree*headptr=NULL;
headptr=(BiTree*)malloc(sizeof(BiTree)); //申请根的头结点,并用头结点的左孩子指向根
printf("输入先序序列:\n");
scanf("%s",Preorder);
printf("输入中序序列:\n");
scanf("%s",Inorder);
int first=0;
Pre_In_Build(first,0,strlen(Inorder)-1,headptr->lchild);
Destroy_Tree(headptr->lchild);
//后序遍历销毁二叉树
void Destroy_Tree(BiTree*&Tptr)
{
if(Tptr->lchild)
{
Destroy_Tree(Tptr->lchild);
}
if(Tptr->rchild)
{
Destroy_Tree(Tptr->rchild);
}
free(Tptr);
}
void Pre_In_Build(int &first,int start,int end,BiTree*&Tptr) //对Preorder[]数组进行遍历,一个一个将Inorder[]数组分成左子树和右子树
{ //并用递归实现此类问题的求解,注意这里的first是要随着每次比对都要加1的
if(start>end) //不能一返回,就改变其的值
{
Tptr=NULL;
return;
}
else
{
int seat;
while(Inorder[seat]!=Preorder[first])
seat++;
Tptr=(BiTree*)malloc(sizeof(BiTree));
Tptr->ch=Preorder[first];
first++;
Pre_In_Build(first,start,seat-1,Tptr->lchild);
Pre_In_Build(first,seat+1,end,Tptr->rchild);
}
}