您的位置:首页 > 职场人生

《剑指Offer》学习笔记--面试题6:重建二叉树

2015-05-05 11:35 633 查看
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出此二叉树并输出它的头结点。二叉树节点的定义如下:

struct BinaryTreeNode

{

int m_nValue;

BinaryTreeNode* m_pLeft;

BinaryTreeNode* m_pRight;

};

解题思路:在二叉树的前序遍历序列中,第一个数字总是树的根结点的值。但在中序序列中,根结点的值在序列的中间,左子树的结点的值位于根节点的值的左边,而右子树的结点的值位于根结点的值的右边。因此我们需要扫描中序遍历序列,才能找到根结点的值。

在想清楚如何在前序遍历和中序遍历的序列中确定左、右子树的子序列之后,我们可以写出如下的递归代码:

#include <iostream>
using namespace std;
typedef struct BinaryTreeNode{
int                  data;
struct BinaryTreeNode* lchild;
struct BinaryTreeNode* rchild;
};

BinaryTreeNode* ConstructCore
(
int *startPreorder, int *endPreorder,
int *startInorder,  int *endInorder
);

BinaryTreeNode* Construct(int *preorder, int *inorder, int length)
{
if(preorder == NULL || inorder == NULL || length <= 0){
return NULL;
}
return ConstructCore(preorder, preorder+length-1, inorder, inorder+length-1);
}

BinaryTreeNode* ConstructCore
(
int *startPreorder, int *endPreorder,
int *startInorder,  int *endInorder
)
{
//前序遍历序列第一个数字是根结点的值
BinaryTreeNode* root = new BinaryTreeNode();
int rootValue = startPreorder[0];
root->data = rootValue;
root->lchild = root->rchild = NULL;

if(startPreorder == endPreorder){
if(startInorder == endInorder
&& *startPreorder == *startInorder)//只有一个节点了
return root;
else
throw std::exception("Invalid input.");
}

//在中序遍历中找到根结点的值
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->lchild = ConstructCore(startPreorder+1, leftPreorderEnd,
startInorder, rootInorder-1);
}
if(leftLength < endPreorder - startPreorder){
//构建右子树
root->rchild = ConstructCore(leftPreorderEnd+1, endPreorder,
rootInorder+1, endInorder);
}
return root;
}
//打印出构建后二叉树的后序遍历序列
void PrintLorder(BinaryTreeNode *root)
{
if(root != NULL){
PrintLorder(root->lchild);
PrintLorder(root->rchild);
cout<<root->data<<" ";
}
}
int main()
{
int preOrder[] = {1,2,4,7,3,5,6,8};
int inOrder[] = {4,7,2,1,5,3,8,6};
int length = sizeof(preOrder)/sizeof(int);
BinaryTreeNode *root = Construct(preOrder, inOrder, length);
PrintLorder(root);
system("pause");
return 0;
}
在函数ConstrucCore中,我们先根据前序遍历序列的第一个数字创建根结点,接下来在中序序列中找出根结点的位置,这样就能确定左、右子树结点的数量。在前序遍历和中序遍历的序列中划分了左、右子树结点的值之后,我们就可以递归地调用函数ConstructCore,分别构建它的左右子树。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: