【算法/c++】利用中序遍历和后序遍历建二叉树

目录

题目:树的遍历

前言

如果不是完全二叉树,使用数组模拟树,会很浪费空间。

题目来源

本题来自 PTA 天梯赛。
题目链接 : 树的遍历

题目描述

给定一棵二叉树的后序遍历和中序遍历序列,输出其层序遍历的序列。假设树中节点的键值均为互不相同的正整数。

输入格式

  • 第一行:一个正整数 N(≤30),表示二叉树的节点个数。
  • 第二行:后序遍历序列,数字间以空格分隔。
  • 第三行:中序遍历序列,数字间以空格分隔。

输出格式

  • 输出层序遍历序列,数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例

plaintext 复制代码
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例

plaintext 复制代码
4 1 6 3 5 7 2

树的数组存储

基本思想

通过数组的索引关系表示树的父子结构,无需显式存储指针。

存储规则

  1. 根节点 存储在索引 1(注意不是 0)。
  2. 对于任意节点 i
    • 左子节点索引2 * i
    • 右子节点索引2 * i + 1
    • 父节点索引i / 2(整数除法)

示例

假设有一棵二叉树:

我们可以通过一个数组去存储

树的索引对应数组的索引,树节点的值存在数组里。

建树算法

关键思路

  • 后序遍历:最后一个元素是根节点
  • 中序遍历:根节点左边是左子树,右边是右子树
  • 递归构建:分别处理左右子树

后序遍历:

结构: 左子树 --- 右子树 --- 根

中序遍历:

结构: 左子树,根,右子树

我们通过中序遍历找到根,就能知道左子树的个数,那么我们就能找到后序遍历左子树的范围,从而得知左子树的根。右子树同理。

算法过程:

1.确定根节点:

  • 从后序遍历序列中取出最后一个元素,这就是当前子树的根节点
  • 将这个根节点存入我们构建的树结构中

2.在中序序列中定位根节点:

  • 在中序遍历序列中查找这个根节点的位置
  • 这个位置将中序序列分为左子树和右子树两部分

3.递归构建左右子树

代码

参数说明

  • root 后序序列中当前子树的根节点索引
  • start 中序序列中当前子树的起始索引
  • ed 中序序列中当前子树的结束索引
  • idx 当前节点在tree数组中的存储位置

变量说明

  • post 为后序遍历数组
  • in 为中序遍历数组
  • tree为存储树的数组
cpp 复制代码
//根据中序遍历和后续遍历构造树
void build(int root,int start,int ed,int idx)
{
    if(start>ed) return;

    //后序知道树根,直接构造数组树
    tree[idx] = post[root];

    //在中序遍历中找根位置,用来区分后序遍历左右子树位置
    int i = start;
    while(i<ed && in[i] != post[root]) i++;

    //构造左子树
    build(root - ed+i-1,start,i-1,idx*2);
    //构造右子树
    build(root - 1,i+1,ed,idx*2+1);
}

总代码

cpp 复制代码
#include <iostream>
using namespace std;
#include <vector>

const int N = 1e5+10;
int n;
int post[N],in[N];
vector<int> tree(N,-1);

//根据中序遍历和后续遍历构造树
void build(int root,int start,int ed,int idx)
{
    if(start>ed) return;

    //后序知道树根,直接构造数组树
    tree[idx] = post[root];

    //在中序遍历中找根位置,用来区分后序遍历左右子树位置
    int i = start;
    while(i<ed && in[i] != post[root]) i++;

    //构造左子树
    build(root - ed+i-1,start,i-1,idx*2);
    //构造右子树
    build(root - 1,i+1,ed,idx*2+1);
}


int main()
{
    cin  >> n;
    for(int i = 1;i<=n;i++)
        cin >>  post[i];
    for(int i = 1;i<=n;i++)
        cin >> in[i];

    build(n,1,n,1);

    vector<int> ans;
    for(int i = 1;i<tree.size();i++)
        if(tree[i] !=-1) ans.push_back(tree[i]);

    for(int i = 0;i<ans.size();i++)
        if(i != ans.size()-1)cout << ans[i]  <<  ' ';
        else cout << ans[i];

    return 0;
}

链表法

思路是差不多的

cpp 复制代码
#include <iostream>
#include <queue>

using namespace std;
const int N  =50;
int n;
int post[N],in[N];

struct node
{
    int val;
    node* left;
    node* right;
};

node* build(int root,int start,int ed)
{
   if(start>ed) return nullptr;

    //创建结点
    node * p = (node *) malloc(sizeof(node));
    p->val = post[root];

    //在中序遍历中找根位置,用来区分后序遍历左右子树位置
    int i = start;
    while(i<ed && in[i] != post[root]) i++;

    p->left = build(root - ed+i-1,start,i-1);
    p->right = build(root - 1,i+1,ed);

    return p;
}


void dfs(node *p)
{
    queue<node> q;
    q.push(*p);
    while(q.size())
    {
        node temp = q.front();
        q.pop();
        if(temp.val != p->val)cout << " ";
        cout << temp.val;
        if(temp.left != nullptr)  q.push(*temp.left);
        if(temp.right != nullptr) q.push(*temp.right);
    } 
}

int main()
{
    cin >> n;
    for(int i = 1;i<=n;i++)
        cin >>  post[i];
    for(int i = 1;i<=n;i++)
        cin >> in[i];

    node* head = build(n,1,n);

    dfs(head);

    return 0;
}
相关推荐
十五年专注C++开发1 分钟前
DocxFactory: 一个C++操作word的开源库(不依赖office控件)
c++·开源·word·后端开发
麦烤楽鸡翅5 分钟前
小红书推荐系统(牛客)
java·python·算法·秋招·春招·牛客·面试算法题
屁股割了还要学13 分钟前
【C++进阶】STL-string的简单实现
c语言·开发语言·数据结构·c++·学习·考研
王哈哈^_^15 分钟前
CV三大核心任务:目标检测、图像分割、关键点检测
人工智能·算法·yolo·目标检测·计算机视觉·视觉检测
..空空的人16 分钟前
C++基于websocket的多用户网页五子棋 --- 项目设计
c++·个人开发
wefg11 小时前
【数据结构】红黑树
数据结构·算法
饼瑶1 小时前
基于AutoDL远端服务复现具身智能论文OpenVLA
算法
Mr.Winter`1 小时前
无人船 | 图解基于MPC控制的路径跟踪算法(以全驱动无人艇WAMV为例)
人工智能·算法·机器人·自动驾驶·ros·路径规划
咪咪渝粮1 小时前
112.路径总和
java·数据结构·算法
高洁011 小时前
大模型-详解 Vision Transformer (ViT) (2
深度学习·算法·aigc·transformer·知识图谱