剑指offer--据前序和中序遍历重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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));  
    }  
      
}  

其实还可以优化,就是利用栈和队列来实现,相对来说较递归要好理解一些。
其实这还出现一些问题,倘若出现相同元素怎么处理,这就需要下去继续深究了

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值