-
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。
-
输入可能包含多个测试样例,对于每个测试案例,
输入的第一行为一个整数n(1<=n<=1000):代表二叉树的节点个数。
输入的第二行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的前序遍历序列。
输入的第三行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的中序遍历序列。
-
对应每个测试案例,输出一行:
如果题目中所给的前序和中序遍历序列能构成一棵二叉树,则输出n个整数,代表二叉树的后序遍历序列,每个元素后面都有空格。
如果题目中所给的前序和中序遍历序列不能构成一棵二叉树,则输出”No”。
-
81 2 4 7 3 5 6 84 7 2 1 5 3 8 681 2 4 7 3 5 6 84 1 2 7 5 3 8 6
-
7 4 2 5 8 6 3 1 No
-
题目描述:
-
输入:
-
输出:
-
样例输入:
-
样例输出:
重建二叉树
第一:对于一棵树可以根据其先序遍历(根左右)和中序遍历(左根右) 或是后序遍历(左右根)和中序遍历(左根右)来重建其二叉树。
那么能不能由先序遍历和后续遍历重建二叉树呢?显然是不可以的!因为先序遍历和后续遍历都只能确定根节点,而无法确定左右子树的边界。所以无法递归下去。
而对于第一行中提及的另外两种情况都是可以的,因为根据先序或是后续遍历可以唯一确定树的根节点,再根据中续遍历可以确定出左右子树。递归,直到叶子节点。则可重建出二叉树。
第二:算法的核心:就是递归建树。
第三:算法的思想:
1、先序遍历的第一个元素或后序遍历的最后一个元素必定是根节点,可以由此获取二叉树的根节点。
2、根据根节点,在中序遍历序列中查找该节点,由中序遍历的性质可知,中序遍历中该根节点左边的序列必定在根节点的左子树中,而根节点右边的序列必定在右子树中。由此可以知道先序遍历中左子树以及右子树的起止位置。
3、分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时(注意这一句话非常关键,这是递归是否结束的条件,代码实现时的关键),说明已经到达叶子节点,遍历完毕。
实现代码如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
struct node *leftnode;
struct node *rightnode;
int value;
}BinaryTreeNode;
int flag;
//输出先序遍历
void preorderTraverse(BinaryTreeNode *p)
{
//I think there is not difference having it or not.
//if the initial value of 'p' is NULL 'if' sentence will be useful!!!
if(NULL==p)
{
return 0;
}
printf("%d ",p->value);
if(NULL!=p->leftnode)
{
preorderTraverse(p->leftnode);
}
if(NULL!=p->rightnode)
{
preorderTraverse(p->rightnode);
}
}
//输出中序遍历
int inorderTraverse(BinaryTreeNode *p)
{
if(NULL==p)
{
return 0;
}
if(NULL!=p->leftnode)
{
inorderTraverse(p->leftnode);
}
printf("%d ",p->value);
if(NULL!=p->rightnode)
{
inorderTraverse(p->rightnode);
}
}
//输出后序遍历
int postorderTraverse(BinaryTreeNode *p)
{
if(NULL==p)
{
return 0;
}
if(NULL!=p)
{
postorderTraverse(p->leftnode);
}
if(NULL!=p)
{
postorderTraverse(p->rightnode);
}
printf("%d ",p->value);
}
BinaryTreeNode* recusiveBuildBinaryTree(int *pPreStart,int *pPreEnd,int *pInStart,int *pInEnd,int n)
{
BinaryTreeNode *pRoot=NULL;
int rootvalue=0;
int i=0;
int *leftPreStart,*leftPreEnd,*rightPreStart,*rightPreEnd;
int *leftInStart,*leftInEnd,*rightInStart,*rightInEnd;
rootvalue=pPreStart[0];
pRoot=(BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
pRoot->value=rootvalue;
pRoot->leftnode=pRoot->rightnode=NULL;
while(rootvalue!=pInStart[i])
{
i++;
if(i>=n)
{
flag=0;
return NULL;
}
}
leftPreStart=pPreStart+1;
leftPreEnd=pPreStart+i;
leftInStart=pInStart;
leftInEnd=pInStart+i-1;
rightPreStart=pPreStart+i+1;
rightPreEnd=pPreEnd;
rightInStart=pInStart+i+1;
rightInEnd=pInEnd;
<span style="white-space:pre"> </span>///此处之上为创建本节点,并为下次递归做好准备。
if(leftInStart<=leftInEnd)///临界条件真是个大难题。
{
pRoot->leftnode=recusiveBuildBinaryTree(leftPreStart,leftPreEnd,leftInStart,leftInEnd,i);
}
if(rightInStart<=rightInEnd)
{
pRoot->rightnode=recusiveBuildBinaryTree(rightPreStart,rightPreEnd,rightInStart,rightInEnd,n-i-1);
}
return pRoot;
}
BinaryTreeNode* buildBinaryTree(int *pPre,int *pIn,int n)
{
BinaryTreeNode *root=NULL;
if(pPre==NULL && pIn==NULL)
{
printf("malloc failed");
}
root=recusiveBuildBinaryTree(pPre,pPre+n-1,pIn,pIn+n-1,n);
return root;
}
int main()
{
int n=0;
int i=0,j=0;
int *pPreorder=NULL;
int *pInorder=NULL;
BinaryTreeNode *root=NULL;
while(scanf("%d",&n))
{
flag=1;
pPreorder=malloc(sizeof(int)*n);
pInorder=malloc(sizeof(int)*n);
for(i=0;i<n;i++)
{
scanf("%d",&pPreorder[i]);
}
for(i=0;i<n;i++)
{
scanf("%d",&pInorder[i]);
}
root=buildBinaryTree(pPreorder,pInorder,n);
if(flag==1)
{
postorderTraverse(root);
printf("\n");
}
else
{
printf("No\n");
}
}
return 0;
}
这段代码提交到九度online judge上之后提示:Output Limit Exceeded : 输出超过限制,你的输出比正确答案长了两倍。
目前还未解决这个问题!