您的位置:首页 > Web前端

剑指Offer——由二叉树的前序中序重构

2016-07-20 11:20 363 查看
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},

则重建二叉树。

(测试用例中,"树"的输出形式类似于树的层次遍历,没有节点的用#来代替)

先序遍历:先遍历根节点,再遍历左子树,再遍历右子树,对子树采用相对规则遍历。

中序序遍历:先遍历左子树,然后遍历右子树,最后遍历根节点,对子树采用相同规则。

分析:

 

1:前序遍历的第一个元素,一定是这个树的根节点

2:对每棵树遍历中序遍历序列,找到与根节点元素相等节点的位置pos,根据中序遍历的特点,根节点向左的序列为左子树的中序遍历序列{4, 7, 2},根节点向右的序列为右子树的中序遍历序列{5, 3,  8, 6}.

3:根据根节点的位置可以节点的位置,可以分别求出,左右子树节点数量,这样可以在前序遍历中确认,左右子树的的前序遍历分别为{2, 4, 7},{3, 5, 6, 8}

4:对左右子树重复1,2,3步,递归求解

5:递归返回条件,一个节点不存在子树时返回。

struct BinaryTreeNode
{
int val;
BinaryTreeNode* left;
BinaryTreeNode* right;
};
void TreeBuild(BinaryTreeNode *root,int *pre,int *mid,int n)
{
if(n<=0) return;
int i;
root->data=pre[0];
for(i=0;i<n;i++)
{
if(mid[i]==root->data)
break;//在中序遍历中寻找左子树的长度为i.
}
if(i>0)//左子树不为空
{
root->left=new BinaryTreeNode();
TreeBuild(root->left,pre+1,mid,i);
}
if(i<n-1)//右子树不为空
{
root->right=new BinaryTreeNode();
TreeBuild(root->right,pre+i+1,mid+i+1,n-i-1);
}
}
//剑指Offer给的解题思路
BinaryTreeNode *TreeBuildCore(int *pre1,int *pre2,int *mid1,int *mid2)//pre1与pre2分别代表二叉树前序遍历的开始和结束指针
{
int rootval=pre1[0];//头结点的值
BinaryTreeNode *root=new BinaryTreeNode();//新建根结点
root->val=rootval;
root->left=root->right=NULL;
if(pre1==pre2)
{
if(mid1==mid2&&*pre1==*mid1)
return root;//只有一个结点
else
throw std::exception("Invalid input");
}
int *rootmid=mid1;
//在中序遍历中查找根节点位置
while(rootmid<=mid2&&rootmid!=rootval)
rootmid++;

if(rootmid==mid2&&*rootmid!=rootval)//在中序遍历中未找到头结点,报错
throw std::exception("Invalid input");

int leftlen=rootmid-mid1;//左子树的长度
int *leftpre2=pre1+leftlen;
if(leftlen>0)
{
//左子树不为空
root->left=TreeBuildCore(pre1+1,leftpre2,mid1,rootmid-1);
}
if(leftlen<pre2-pre1)
{
//右子树不为空
root->right=TreeBuildCore(leftpre2+1,pre2,rootmid+1,mid2);
}
return root;
}
BinaryTreeNode *TreeBulid(int *pre,int *mid,int length)
{
if(pre==NULL||mid==NULL||length<=0)
return NULL;
return TreeBuildCore(pre,pre+length-1,mid,mid+lenght-1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: