重建二叉树

重建二叉树
  • 参与人数:1892时间限制:1秒空间限制:32768K
  • 通过比例:19.08%
  • 最佳记录:0 ms|0K(来自  shi_kai)

题目描述

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

二叉树,先回顾下二叉树的特点:

关于二叉树;n总=n0+n1+n2;n0=n2 + 1 ;so…n总=n1+2*n2+1

每层的最大结点数2^(n-1);    结点总数最大是2^n - 1

 

关于遍历:先序是:根左右;

                  中序是:左根右;

                  后序是:左右根;

一般我们会选择递归的方法来遍历这样代码回简单些;这题也是一样的。

但由于已经给出了函数的框架,所以代码回收到限制;

思路还是递归,方法是分段递归;

/*
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };
TreeNode *root;*/
class Solution {
public:
  struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
        //判定递归终止条件;
        if(pre.size() == 0 || in.size() == 0) {
            return NULL;
        }
        //定义Node节点并其求根节点;
        int root = pre[0];
        TreeNode* node = new TreeNode(root);
        vector<int>::iterator it;
        //求左右子树的遍历序列;
        vector<int> preLeft, preRight, inLeft, inRight;
        //1、求根节点在中序遍历序列中的位置;
        vector<int>::iterator i;
        for(it = in.begin(); it != in.end(); it++) {
            if(root == *it) {
                i = it;
            }
        }
        //2、求左右子树的中序遍历子序列;
        int k = 0;
        for(it = in.begin(); it != in.end(); it++) {
            if(k == 0)
                inLeft.push_back(*it);
            else if(k == 1)
                inRight.push_back(*it);

            if(it == i)
                k = 1;
        }
        //3、求左右子树的前序遍历子序列;
        k = 0;
        vector<int>::iterator ite;
        for(it = pre.begin()+1; it != pre.end(); it++)
        {
            for(ite = inLeft.begin(); ite != inLeft.end(); ite++)
            {
                if(*it == *ite)
                {
                    preLeft.push_back(*it);
                    k = 1;
                }
            }
            if(k == 0)
            {
                preRight.push_back(*it);
            }
            k = 0;
        }
        //根据遍历序列求出跟的左右节点;
        node->left = reConstructBinaryTree(preLeft,inLeft);
        node->right = reConstructBinaryTree(preRight,inRight);
        //返回节点地址;
        return node;
    }
};


 

学会了方法可以在HDUOJ上做一个,练习一下;

题意是:已知先序和中序输出二叉树的后序!

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1710

 

249ms AC

 

#include<stdio.h>
#include<vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };
TreeNode *root;
class Solution {
public:
  struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
        //判定递归终止条件;
        if(pre.size() == 0 || in.size() == 0) {
            return NULL;
        }
        //定义Node节点并其求根节点;
        int root = pre[0];
        TreeNode* node = new TreeNode(root);
        vector<int>::iterator it;
        //求左右子树的遍历序列;
        vector<int> preLeft, preRight, inLeft, inRight;
        //1、求根节点在中序遍历序列中的位置;
        vector<int>::iterator i;
        for(it = in.begin(); it != in.end(); it++) {
            if(root == *it) {
                i = it;
            }
        }
        //2、求左右子树的中序遍历子序列;
        int k = 0;
        for(it = in.begin(); it != in.end(); it++) {
            if(k == 0)
                inLeft.push_back(*it);
            else if(k == 1)
                inRight.push_back(*it);

            if(it == i)
                k = 1;
        }
        //3、求左右子树的前序遍历子序列;
        k = 0;
        vector<int>::iterator ite;
        for(it = pre.begin()+1; it != pre.end(); it++)
        {
            for(ite = inLeft.begin(); ite != inLeft.end(); ite++)
            {
                if(*it == *ite)
                {
                    preLeft.push_back(*it);
                    k = 1;
                }
            }
            if(k == 0)
            {
                preRight.push_back(*it);
            }
            k = 0;
        }
        //根据遍历序列求出跟的左右节点;
        node->left = reConstructBinaryTree(preLeft,inLeft);
        node->right = reConstructBinaryTree(preRight,inRight);
        //返回节点地址;
        return node;
    }
};

/***后序遍历***左右根***/
void posOrderRecur(TreeNode *head){
    if(head==NULL) return ;
    posOrderRecur(head->left);
    posOrderRecur(head->right);
    if(head==root)
        printf("%d\n",head->val);
    else
        printf("%d ",head->val);
}
int main()
{
    int n;
    Solution so;
    while(scanf("%d",&n)>0)
    {
        root=new TreeNode(NULL);
        vector<int> a,b;
        int x;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            a.push_back(x);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            b.push_back(x);
        }
        root=so.reConstructBinaryTree(a,b);
        TreeNode *h=root;
        posOrderRecur(h);
    }
    return 0;
}


 

然后在提供一种数组递归的,利用指针,会方便很多呢。

46ms AC

#include<stdio.h>
#include<vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };
TreeNode *root;

TreeNode *Creat(int *pre,int *in,int n)
{
    TreeNode *s;
    for(int i=0;i<n;i++)
    {
        if(pre[0]==in[i])
        {
            s=new TreeNode(in[i]);
            //中序历遍中在根节点左边的都是左子树上的
            s->left=Creat(pre+1,in,i);
            //在根节点右边的,都是右子树上的,右子树需要从i+1开始
            s->right=Creat(pre+i+1,in+i+1,n-i-1);
            return s;
        }
    }
    return NULL;
}
/***后序遍历***左右根***/
void posOrderRecur(TreeNode *head){
    if(head==NULL) return ;
    posOrderRecur(head->left);
    posOrderRecur(head->right);
    if(head==root)
        printf("%d\n",head->val);
    else
        printf("%d ",head->val);
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        root=NULL;
        int a[2005],b[2005];
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&b[i]);
        root=Creat(a,b,n);
        TreeNode *head=root;
        posOrderRecur(head);
    }
    return 0;
}

你可能感兴趣的:(二叉树,剑指offer)