输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
分析:此时不由得想起前序遍历的顺序是根--左--右
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
struct BTreeNode
{
int _value;
BTreeNode*_left;
BTreeNode*_right;
};
//解法一
BTreeNode* RebuildCode(int * PreStart,int *PreEnd,int *InStart,int *InEnd);
BTreeNode* RebuildTree(int *PreOrder,int *InOrder,int len)
{
//首先判断边界条件
if(PreOrder == NULL || InOrder == NULL ||len <= 0)
{
return NULL;
}
else
{
return RebuildCode(PreOrder,PreOrder+len-1,InOrder,InOrder+len-1);
}
}
BTreeNode* RebuildCode(int * PreStart,int *PreEnd,int *InStart,int *InEnd)
{
BTreeNode *root = new BTreeNode();
//新建节点root保存前序第一个节点为根结点
root->_value = PreStart[0];
root-> _left = NULL;
root->_right = NULL;
if(InStart == InEnd && *InStart == *InEnd)
{
return root;
}
//据此节点找到中序遍历此节点的位置
int *rootIn = InStart;
while(*PreStart != *rootIn)
{
rootIn++;
}
//左子树的长度
int leftlen = rootIn-InStart;
//重建左子树
if(leftlen > 0)
{
root->_left = RebuildCode( PreStart+1,PreStart+leftlen,InStart,InStart+leftlen-1);
}
//重建右子树
if(InStart+leftlen < InEnd)
{
root->_right = RebuildCode( PreStart+leftlen+1,PreEnd,InStart+leftlen+1,InEnd);
}
return root;
}
//后序遍历输出二叉树序列
void PostOrder(BTreeNode *root)
{
if(root->_left != NULL)
{
PostOrder(root->_left);
}
if(root->_right != NULL)
{
PostOrder(root->_right);
}
if(root != NULL)
{
cout<<root->_value<<" ";
}
}
int main()
{
int PreOrder[8] = {1,2,4,7,3,5,6,8};
int InOrder[8] = {4,7,2,1,5,3,8,6};
BTreeNode *root = NULL;
PostOrder(RebuildTree(PreOrder,InOrder,8));
system("pause");
return 0;
}
//解法二
void RebuildTree(int * PreOrder,int *InOrder,int len,BTreeNode ** root)
{
if(PreOrder == NULL || InOrder == NULL)
{
return;
}
BTreeNode*tmp = new BTreeNode();
tmp->_value = PreOrder[0];
tmp->_left = NULL;
tmp->_right = NULL;
if( root == NULL)
{
*root = tmp;
}
if(len == 1)
{
return;
}
int *OriOrder = InOrder;
int *LeftEnd = InOrder;
int tmplen = 0;
//找到左子树的结尾
while(*PreOrder != *LeftEnd)
{
if(PreOrder == NULL || LeftEnd == NULL)
{
return;
}
tmplen++;
if(tmplen>len)
{
break;
}
LeftEnd++;
}
//计算左子树的长度
int leftlen = 0;
leftlen = LeftEnd-OriOrder;
//计算右子树的长度
int rightlen = 0;
rightlen = len-leftlen-1;
//重建左子树
if(leftlen > 0)
{
RebuildTree(PreOrder+1,InOrder,leftlen,&((*root)->_left));
}
//重建右子树
if(rightlen < 0)
{
RebuildTree(PreOrder+leftlen+1,InOrder+leftlen+1,rightlen, &((*root)->_right));
}
}
其实还可以优化,就是利用栈和队列来实现,相对来说较递归要好理解一些。
其实这还出现一些问题,倘若出现相同元素怎么处理,这就需要下去继续深究了