【九度oj】1385 重建二叉树

原题地址:http://ac.jobdu.com/problem.php?pid=1385

题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 {1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。


算法描述:

前序遍历:根左右;中序遍历:左根右;后序遍历:左右根。

前序遍历序列 {1,2,4,7,3,5,6,8} 中,前序序列中的第一个元素:1作为根将中序遍历序列 {4,7,2,1,5,3,8,6} 分为两部分,这两部分分别对应前序遍历序列中的两部分。

即:子前序遍历序列 {2, 4, 7} 和子中序遍历序列 {4, 7, 2} 。然后迭代使用前序序列中的第一个元素作为分隔符将中序遍历序列隔成两个序列。

分成三个函数:主函数、midFind(找到前序序列第一个对应在中序序列的分隔位置)、post(主迭代函数)。

post 中如果出现的 left 和 right 分别代表子树的范围(前序、中序的子树范围大小关系是一致的),如果:

(1)left > right,则此子树为空;(2)left == right,则此子树仅有一个根节点;(3)left < right,继续迭代。

注意:

这题最坑爹的地方,如果是(1)为空子树则不用判断;如果是(3)迭代时需要用 midFind 寻找判断是否元素存在;但是如果是(2)仅有一个根节点时,我忘记比较前序的根节点与后序的根节点是否是同一元素,不是一个元素则说明前序、中序不是同一个二叉树。

同时,再次迭代的顺序一定不能错,要记录后序序列,所以 post 按照 left - right - root 顺序引用。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1005

using namespace std;

int preArray[MAX];
int midArray[MAX];
int postArray[MAX];
int postIndex;

int midFind(int *array, int left, int right, int target)
{
    for(int i=left; i <= right; i++)
    {
        if(array[i] == target)
            return (i - left);
    }
    return MAX;                       // return MAX; means "end" 
}
    
int post(int preLeft, int preRight, int midLeft, int midRight)
{
    //  1. empty subtree  
    if(preLeft > preRight || midLeft > midRight)
        return 1;
    
    //  2. subtree is just a root node  
    if(preLeft == preRight || midLeft == midRight){
        if (preArray[preLeft] != midArray[midLeft])
            return 0;
        else{
            postArray[postIndex] = preArray[preLeft];
            postIndex ++;
            return 1;
        }
    }
     
    //  3. normal subtree   
    int midOffset = midFind(midArray, midLeft, midRight, preArray[preLeft]);
    if(midOffset == MAX)              // can't find the target 
    {
        return 0;
    }
    else
    {
        // 此处 if 顺序一定不能错,要记录后序所以 post 按照 left - right - root 顺序 
        if( post(preLeft + 1, preLeft+midOffset, midLeft, midLeft+midOffset - 1) && 
            post(preLeft+midOffset + 1, preRight, midLeft+midOffset + 1, midRight))
        {
            postArray[postIndex] = preArray[preLeft];
            postIndex ++;
            return 1;
        }
        else
            return 0;
    }
}

int main(){
    int n;
    while(scanf("%d", &n)==1)
    {
        memset(preArray, 0, MAX);
        memset(midArray, 0, MAX);
        memset(postArray, 0, MAX);
        postIndex = 0;
        
        for(int i=0; i<n; i++)
            scanf("%d", &preArray[i]);
            
        for(int i=0; i<n; i++)
            scanf("%d", &midArray[i]);
        
        int result = post(0, n-1, 0, n-1);
        if(result){
            for(int i =0; i<n-1; i++)
                printf("%d ", postArray[i]);
            printf("%d \n", postArray[n-1]);
        }
        else{ 
            printf("No\n");
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值