http://acm.hdu.edu.cn/showproblem.php?pid=1710
由前序和中序结果求后序遍历结果
树的遍历
给你一棵树的先序遍历结果和中序遍历的结果,让你求以后序遍历输出用递归。每次把两个数组分成三个部分,父节点,左子树,右子树,把父节点放到数组里边,重复此步骤直到重建一棵新树, 这时,数组里元素刚好是后序遍历的顺序
关键点:
中序遍历的特点是先遍历左子树,接着根节点,然后遍历右子树。这样根节点就把左右子树隔开了。
而前序遍历的特点是先访问根节点,从而实现前序遍历结果提供根节点信息,中序遍历提供左右子树信息,从而实现二叉树的重建。
代码:
#include<iostream>
#include<stack>
#define N 1005
using namespace std;
stack<int> s; //存放父节点
int pre[N],in[N],a[N]; //先序数组和后序数组
void make(int preleft,int preright,int inleft,int inright)
{
int parent,leftsize,rightsize;
for(parent=inleft;parent<=inright;parent++)
if(in[parent]==pre[preleft])
break; //找到父节点在中序遍历的位置parent
leftsize=parent-inleft; rightsize=inright-parent; //获得左树和右树的大小
if(leftsize>0)
make(preleft+1,preleft+leftsize,inleft,parent-1); //如果有左子树,递归重建左子树
if(rightsize>0)
make(preleft+leftsize+1,preright,parent+1,inright); //如果有右子树,递归重建右子树
s.push(in[parent]); //父节点入栈
}
int main()
{
int i,n,num;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
scanf("%d",&pre[i]);
for(i=0;i<n;i++)
scanf("%d",&in[i]); //输入
make(0,n-1,0,n-1); //建树
i=0;
while(!s.empty())
{
a[i++]=s.top();
s.pop();
} //处理结果
for(i=n-1;i>0;i--)
printf("%d ",a[i]);
printf("%d\n",a[0]); //输出
}
return 0;
}
注: 已知二叉树的前序和中序遍历, 可以唯一确定二叉树的后序遍历, 但如果知道前序和后序,求中序遍历是不可能实现的.
算法: 由前序遍历的第一个元素可确定左、右子树的根节点,参照中序遍历又可进一步确定子树的左、右子树元素。如此递归地参照两个遍历序列,最终构造出二叉树。
代码如下:
char preorder[100]; char inorder[100];
void buildTree(int preLeft,int preRight, int inLeft, int inRight)
{
int parent, leftSize, rightSize;
if (preLeft <= preRight && inLeft <= inRight)
{
//在中序中遍历寻找父节点
for (parent = inLeft; parent <= inRight; ++parent)
{
if (inorder[parent] == preorder[preLeft])
break;
}
//获得左树和右树的大小
leftSize = parent - inLeft; rightSize = inRight - parent;
//如果有左子树,递归重建左子树
if (leftSize > 0)
{ buildTree(preLeft + 1, preLeft + leftSize, inLeft, parent - 1); }
//如果有右子树,递归重建右子树
if (rightSize > 0 )
{ buildTree(preLeft + leftSize + 1, preRight, parent + 1 , inRight); }
//若无子树,打印父节点
printf("%c " , inorder[parent]);
}
}