二叉树-构造二叉树

1.基本思路

例如要构造如下二叉树:
在这里插入图片描述
已知:
前序序列preorder=9 3 5 6 7 1 2
中序序列inorder=5 3 7 6 9 1 2
或者
中序序列inorder=5 3 7 6 9 1 2
后序序列postorder=5 7 6 3 2 1 9
我们如何构造还原二叉树呢?
以前序序列和中序序列为例:
①首先通过前序遍历获得根结点root。
②根据根结点来划分中序序列。
③已知前序序列和中序序列长度一致,因此就可以来划分前序序列。
④分别获得了左子树的前序序列、中序序列和右子树的前序序列、中序序列。
⑤递归。
具体例子:
前序序列preorder=9 3 5 6 7 1 2
中序序列inorder=5 3 7 6 9 1 2
①根:9
②划分中序序列:
左边部分:5 3 7 6
右边部分:1 2
③划分前序序列:
左边部分:3 5 6 7长度和中序序列左边部分一致
右边部分:1 2
④左子树的前序序列、中序序列:3 5 6 7 和 5 3 6 7
右子树的前序序列、中序序列: 1 2 和 1 2
图示:
在这里插入图片描述

2.前序序列和中序序列构造二叉树

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (inorder.size() == 0 || preorder.size() == 0) {
            return nullptr;
        }
        TreeNode* root = new TreeNode();
        root->val = preorder[0];
        int splitPoint = 0;//分割点
        for (int i = 0; i < inorder.size(); i++) {
            if (inorder[i] == root->val) {
                splitPoint = i;
                break;
            }
        }
        vector<int> inleftorder(inorder.begin(),inorder.begin() + splitPoint); //中序序列左序列
        vector<int> inrightorder(inorder.begin() + splitPoint + 1,inorder.end()); //中序序列右序列
        vector<int> preleftorder(preorder.begin()+1,preorder.begin() + inleftorder.size()+1); //前序序列左序列
        vector<int> prerightorder(preorder.begin() + inleftorder.size()+1,preorder.end()); //前序序列右序列
        root->left = buildTree(preleftorder, inleftorder); //左子树的前序序列和中序序列
        root->right = buildTree(prerightorder, inrightorder); //右子树的前序序列和中序序列
        return root;
    }
};

3.中序序列和后序序列构造二叉树

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size()==0 || postorder.size()==0){
            return nullptr;
        }
        TreeNode* root = new TreeNode();
        root->val=postorder[postorder.size()-1];
        int inleft=0;//分割点
        for(int i=0;i<inorder.size();i++){
            if(inorder[i]==root->val){
                inleft=i;
                break;
            }
        }
        postorder.resize(postorder.size()-1);//后序遍历序列减1
        vector<int> inleftorder(inorder.begin(),inorder.begin()+inleft);//左子树中序序列
        vector<int> inrightorder(inorder.begin()+inleft+1,inorder.end());//右子树中序序列
        vector<int> postleftorder(postorder.begin(),postorder.begin()+inleftorder.size());//左子树后序序列
        vector<int> postrightorder(postorder.begin()+inleftorder.size(),postorder.end());//右子树后序序列
        root->left=buildTree(inleftorder,postleftorder);
        root->right=buildTree(inrightorder,postrightorder);
        return root;
    }
};

4.总结

构造二叉树的过程,如何正确的写出各个子序列的边界是有些困难的,需要在稿纸上认真分析整个过程,确保边界不出错。两种构造方式代码略有不同,对于前序序列的处理,每次递归时都会往后移动一步,因为根结点已经处理过了,避免重复处理。

vector<int> preleftorder(preorder.begin() + 1,preorder.begin() + inleftorder.size() + 1); //后移一步
vector<int> prerightorder(preorder.begin() + inleftorder.size() + 1,preorder.end()); 

后序序列的根结点处理是通过修改后序序列的长度,避免重复处理根结点。

postorder.resize(postorder.size()-1);//后序遍历序列减1

最后,假如已知前序序列后序序列可以唯一还原出二叉树吗,答案是否定的,因为虽然可以确定根结点但无法分出左右子树,会出现不同的二叉树结果。
例如下图:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值