【由二叉树的中序序列和前序序列(后序序列)重建二叉树】

一、回顾前、中、后序遍历

1.1、前序遍历

前序遍历:根左右
代码:

#include<iostream>
#include<vector>

using namespace std;

struct TreeNode{
    int val;
    TreeNode *left;
    TreeNode* right;
};
class Solution{
public:
    void preorder(TreeNode* root,vector<int>&nums){
    if(root == nullptr){
        return;
    }
    nums.push_back(root->val);
    preorder(root->left,nums);
    preorder(root->right,nums);
}

vector<int>preorderTra(TreeNode*root){
    vector<int>res;
    preorder(root,res);
    return res;
}
};

1.2、中序遍历

中序遍历:左根右
代码:

#include<iostream>
#include<vector>

using namespace std;

struct TreeNode{
    int val;
    TreeNode *left;
    TreeNode* right;
};
class Solution{
public:
    void inorder(TreeNode* root,vector<int>&nums){
    if(root == nullptr){
        return;
    }
    inorder(root->left,nums);
    nums.push_back(root->val);
    inorder(root->right,nums);
}

vector<int>inorderTra(TreeNode*root){
    vector<int>res;
    inorder(root,res);
    return res;
}
};

1.3、后序遍历

后序遍历:左右根
代码:

#include<iostream>
#include<vector>

using namespace std;

struct TreeNode{
    int val;
    TreeNode *left;
    TreeNode* right;
};
class Solution{
public:
    void postorder(TreeNode* root,vector<int>&nums){
    if(root == nullptr){
        return;
    }
    postorder(root->left,nums);
    postorder(root->right,nums);
    nums.push_back(root->val);
}

vector<int>postorderTra(TreeNode*root){
    vector<int>res;
    postorder(root,res);
    return res;
}
};

二、由前+中重建二叉树

假设条件:遍历序列中无重复元素
在这里插入图片描述
由于前序遍历是根左右的顺序,可以由前序序列确定根结点的值,再在中序序列中确定根结点的位置,为什么要确定根结点位置呢,因为中序遍历是左根右的顺序,根结点即为左右子树的分界点,而后对左子树和右子树进行同样的操作,这就是一个递归的过程。

拿着根结点的值去中序序列中定位时,可以通过两种方法:

  1. 每次都用指针进行遍历;
  2. 将中序序列装进哈希表中,其中键为根结点的值,值为根结点在中序中的下标。

具体代码如下:

#include<iostream>
#include<vector>
#include<unordered_map>

using namespace std;
struct TreeNode{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x): val(x),left(nullptr),right(nullptr){}
};
class Solution{
private:
    unordered_map<int,int>m;
public:
    TreeNode* buildhelper(vector<int>&preorder,vector<int>&inorder,int preleft,int preright,int inleft,int inright){
        if(preleft > preright){
            return nullptr;
        }
        //在前序中确定根结点
        int root_val = preorder[preleft];
        //在中序中定位根结点
        int root_index = m[root_val];
        //建树
        TreeNode* root = new TreeNode(root_val);
        //左子树
        root->left = buildhelper(preorder,inorder,preleft+1,root_index-inleft+preleft,inleft,root_index-1);
        //右子树
        root->right = buildhelper(preorder,inorder,root_index-inleft+preleft+1,preright,root_index+1,inright);
        return root;
    }
    TreeNode* buildTree(vector<int>&preorder,vector<int>&inorder){
        int num = inorder.size();
        //哈希表存储中序序列,便于定位根结点
        for(int i = 0; i < num; i++){
            m[inorder[i]] = i;
        }
        return buildhelper(preorder,inorder,0,num-1,0,num-1);
    }
};

三、由后+中重建二叉树

假设条件:遍历序列中无重复元素
在这里插入图片描述
和前+中同样的思路,具体代码如下:

#include<iostream>
#include<vector>
#include<unordered_map>

using namespace std;
struct TreeNode{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x): val(x),left(nullptr),right(nullptr){}
};
class Solution{
private:
    unordered_map<int,int>m;
public: 
    TreeNode* buildhelper(vector<int>&postorder,vector<int>&inorder,int postleft,int postright,int inleft,int inright){
        if(postleft > postright){
            return nullptr;
        }
        //在后序中找到根结点
        int root_val = postorder[postright];
        //在中序中定位根结点
        int root_index = m[root_val];
        //建树
        TreeNode* root = new TreeNode(root_val);
        //左子树
        root->left = buildhelper(postorder,inorder,postleft,root_index-inleft+postleft,inleft,root_index-1);
        //右子树
        root->right = buildhelper(postorder,inorder,root_index-inleft+postleft+1,postright-1,root_index+1,inright);
        return root;
    }
    TreeNode* buildTree(vector<int>&postorder,vector<int>&inorder){
        int num = inorder.size();
        for(int i = 0; i < num; i++){
            m[inorder[i]] = i;
        }
        return buildhelper(postorder,inorder,0,num-1,0,num-1);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值