各种序列建树

使用中序加其余序列建树时,会有多次递归,首先使用unordered_map<int,int>将值所在的数组位置保存下来,这样不用每次都去遍历数组便可以获得值所在的数组下标

        if(!preorder.size()) return NULL;
        TreeNode* root=new TreeNode(preorder[0]);
        vector<int> nextpreL,nextpreR,nextinL,nextinR;
        bool tag=true;
        for(int i=0;i<inorder.size();i++){
            if(inorder[i]==preorder[0]){
                tag=0;
                continue;
            }
            if(tag) nextinL.push_back(inorder[i]);
            else nextinR.push_back(inorder[i]);
        }
        int cnt=0;
        for(int i=1;i<preorder.size();i++){
            if(cnt<nextinL.size()){
                cnt++;
                nextpreL.push_back(preorder[i]);
            }
            else nextpreR.push_back(preorder[i]);
        }
        root->left=buildTree(nextpreL,nextinL);
        root->right=buildTree(nextpreR,nextinR);
        return root;

引自力扣105. 从前序与中序遍历序列构造二叉树

中序+层次遍历序列建树

《算法笔记》上只介绍了中序+先序或者中序+后序建树,并且这两种建树其实可以看做是一种情况,先补充一下,当树中的数据严格不同时,如何通过给定的中序遍历序列和层次遍历序列建树。
在这里插入图片描述

如图所示,中序遍历序列是4,2,5,1,3,6。层次遍历序列是1,2,3,4,5,6。无论是根据哪两个序列建树,要是想唯一确立一棵树,必须得是有中序序列,因为中序序列提供的是划分左右子树的依据。而其余的序列起到提供根结点的作用。
仔细观察,可以发现,层次遍历序列的第一个元素是根结点的值,也就是说当前层次遍历序列的第一个结点提供了根结点。通过这一点,可以在中序遍历序列中划分出左右子树,比如说当前根结点为1,在中序遍历序列中1左边的结点4,2,5就是1的左子树中的结点,在中序遍历序列中1的右边的结点3,6即为1的右子树的结点,当前层中可以创建根结点,值为1。
要想递归建树,必须知道对于1的左子树,要知道1的左子树的层次遍历序列2,4,5,以及中序遍历序列4,2,5。而现在已经知道了1的左子树的中序遍历序列了,也就是在原中序遍历序列中的1的左侧数据,关键是要获取当前1的左子树的层次遍历序列。问题转化为从整棵树的层次遍历序列中获取左子树的层次遍历序列。仔细思考层次遍历序列可以,对于任何一颗子树来说,其层次遍历序列在整棵树的层次遍历序列中是按照顺序存放的,比如1的左子树的层次遍历序列为2,4,5。整棵树的层次遍历序列为1,2,3,4,5,6。可以发现2,4,5在整棵树的层次遍历序列中虽然中间穿插了别的数,但是还是按照顺序来存放的。
所以,在获取中序遍历序列时,使用unordered_map < int,int > pos存储下来当前数据的数组下标,这样,在递归建树的每一层,便可以通过level[0]得到当前层的根结点的取值,又可以通过pos[level[0]]直接获取当前层的根节点的中序遍历序列的数组下标,之后从 i 等于1开始遍历当前层的层序遍历序列只要当前数据在中序遍历序列中的位置小于根结点的位置,其就位当前根结点的左子树,否则为当前根结点的右子树。

#include <bits/stdc++.h>

using namespace std;

struct node{
    int val;
    node *lchild,*rchild;
    node(){}
    node(int v):val(v),lchild(nullptr),rchild(nullptr){};
};

const int maxn = 30;
int inorder[maxn];
unordered_map<int,int> pos;//记录位置信息

node* createTree(int inl,int inr,vector<int> &level){
    if(inl > inr) return nullptr;

    node* root = new node(level[0]);

    int k = pos[level[0]];
    vector<int> left,right;
    for(int i = 1;i < level.size();i++){//遍历层次序列
        int cur = level[i];
        if(pos[cur] < k) left.push_back(cur);//如果当前点在中序序列中的位置在当前根结点的左侧
        else right.push_back(cur);//将当前结点加入到left左子树中
    }
    root->lchild = createTree(inl,k-1,left);
    root->rchild = createTree(k+1,inr,right);
    
    return root;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 0;i < n;i++){
         scanf("%d",inorder + i);
         pos[inorder[i]] = i;//记录下每个数据在中序序列中的位置
    }
    
    vector<int> level;
    for(int i = 0;i < n;i++){
        int t;
        scanf("%d",&t);
        level.push_back(t);
    }

    node* root = createTree(0,n-1,level);//根结点
    
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值