《剑指offer》面试题7: 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含有重复的数字。
例如,输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},就可以重建出下图所示的二叉树。
这里顺便介绍一下二叉树的四种遍历:
1、前序遍历:若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。
2、中序遍历: 若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。
3、后序遍历: 若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。
4、层序遍历: 若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。
题解:
#include<iostream>
#include <exception>
using namespace std;
struct BinaryTreeNode
{
int value;
BinaryTreeNode* left;
BinaryTreeNode* right;
};
BinaryTreeNode* ConstructCore(int* startPreorder,int* endPreorder,int* startInorder,int*){
int rootvalue=startPreorder[0];
BinaryTreeNode* root=new BinaryTreeNode();
root->value=rootvalue;
root->left=root->right=NULL;
if(startPreorder==endPreorder){
if(startInorder==endInorder && *startInorder==*startPreorder){
return root;
}
else
throw std::exception("Invalid input.");
//throw表达式包含关键字throw和紧随其后的一个表达式,其中表达式的类型就是抛出的异常类型。
}
int* rootInorder=startInorder;
while(rootInorder<=endInorder && *rootInorder!=rootvalue){
++rootInorder;
}
if(rootInorder==endInorder && *rootInorder!=rootValue)
throw std::exception("Invalid input.");
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;
}
需要理解的是:在代码中有很多看似加减的操作,其实都是指针的移位。