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、根据前序遍历序列和后续遍历序列,求得所有可能的中序遍历序列。