9oj编号1385。剑指6。Leetcode。
题目:根据二叉树的前序遍历序列和中序遍历序列,求得该二叉树的后序遍历序列。Given preorder and inorder traversal of a tree, construct the binary tree.
注意:有个前提,二叉树中的所有元素都不相同。
方法:
根据前序序列和中序序列重建二叉树原型,然后进行后序遍历。所以关键就在于重建二叉树。
使用递归的方法比较容易。如下图所示,对于二叉树的构建过程也是递归的。
首先把当前前序遍历序列的第一个元素作为root结点,并在在中序遍历中找到该root结点元素,那么root元素左边的若干个元素就是该root结点的左子树,root元素右边的若干个元素就是该root结点的右子树。然后递归地去构建各子树。
为了在递归时原地记录遍历序列,参数要记录前序遍历序列的开始指针和结束指针,中序遍历的开始指针和结束指针。
#include <iostream>
#include <cstdio>
using namespace std;
typedef struct BTreeNode{
int value;
BTreeNode *left;
BTreeNode *right;
}Node,*BTree;
void pretraverse(BTree root)
{
if(root != NULL)
{
printf("%d ", root->value);
pretraverse(root->left);
pretraverse(root->right);
}
}
void intraverse(BTree root)
{
if(root != NULL)
{
intraverse(root->left);
printf("%d ", root->value);
intraverse(root->right);
}
}
void posttraverse(BTree root)
{
if(root != NULL)
{
posttraverse(root->left);
posttraverse(root->right);
printf("%d ", root->value);
}
}
BTree ConstructCore(int* startpreorder, int *endpreorder,
int* startinorder, int* endinorder)
{
int rootvalue = startpreorder[0];
BTree root = new Node();
root->value = rootvalue;
root->left = root->right = NULL;
if(startpreorder == endpreorder)
{
if(startinorder == endinorder && *startpreorder==*startinorder)
return root;
else
throw "valid!";
}
//find root in inorder and conpute its location
int *rootinorder = startinorder;
while(rootinorder <= endinorder && *rootinorder != rootvalue)
rootinorder++;
if(rootinorder == endinorder && *rootinorder != rootvalue)
throw "valid!";
int leftlength = rootinorder - startinorder;
int *leftpreorderend = startpreorder + leftlength;
if(leftlength>0)
{
root->left = ConstructCore(startpreorder+1, leftpreorderend,
startinorder, rootinorder-1);
}
if(leftlength < endpreorder - startpreorder)
{
root->right = ConstructCore(leftpreorderend+1, endpreorder,
rootinorder+1, endinorder);
}
return root;
}
BTree Construct(int* preorder, int* inorder, int len)
{
if(preorder == NULL || inorder == NULL || len < 0)
return NULL;
return ConstructCore(preorder, preorder+len-1, inorder, inorder+len-1);
}
int main()
{
int n;
int pre[1000], in[1000];
while(scanf("%d",&n) != EOF)
{
for(int i=0;i<n;i++)
scanf("%d", &pre[i]);
for(int i=0;i<n;i++)
scanf("%d", &in[i]);
try
{
BTree tree = Construct(pre, in, n);
//printf("PostOrder: ");
posttraverse(tree);
printf("\n");
}
catch(...)
{
printf("No\n");
}
}
return 1;
}
LeeCode:
class Solution {
public:
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
int n = preorder.size();
if( n == 0)
return NULL;
return construct(preorder, inorder, 0, n-1, 0, n-1);
}
TreeNode *construct(vector<int> &preorder, vector<int> &inorder, int preleft, int preright, int inleft, int inright)
{
TreeNode *root = new TreeNode(preorder[preleft]);
root->left = root->right = NULL;
if(preleft == preright)
{
return root;
}
int i;
for(i=inleft;i<=inright;i++)
{
if(inorder[i] == preorder[preleft])
break;
}
if(i > inleft)
root->left = construct(preorder, inorder, preleft+1, preleft+i-inleft, inleft, i-1);
if(i < inright)
root->right = construct(preorder, inorder, preleft+i-inleft+1, preright, i+1, inright);
return root;
}
};
编码心得:
1、二叉树遍历的时候在递归时别忘记判断递归结束条件,即指针为null。
2,C++的异常处理方法。g++和vs有一些不同。
一般的,可以在抛出异常时用 throw "出现异常";
捕捉异常用
try
{
捕捉异常
}
catch(...)
{
printf("说点什么\n");
}
当发现输入数据不符合逻辑且当时正处于递归深处时,返回语句不足以快速结束当前的处理过程,此时就可以借助异常处理来快速跳回最外层。
变种题目:
1、根据后序遍历序列和中序遍历序列,求得前序遍历序列。其思想和本题目一致。
2、根据前序遍历序列和后续遍历序列,求得所有可能的中序遍历序列。