7-1 根据后序序列和中序序列确定二叉树

本文介绍如何使用给定的后序遍历序列和中序遍历序列,利用二叉链表在C++中实现二叉树的构建,并计算其深度以及输出先序遍历序列。主要涉及递归的深度优先搜索算法。
摘要由CSDN通过智能技术生成

二叉树采用二叉链表存储,要求根据给定的后序遍历序列和中序遍历序列建立二叉树,并输出二叉树的深度及其先序遍历序列。

输入格式:
测试数据有多组,处理到文件尾。每组测试数据的第一行输入结点数n(1≤n≤10),第二、三行各输入n个整数,分别表示二叉树的后序遍历序列和中序遍历序列。

输出格式:
对于每组测试,在一行上分别输出该二叉树的深度及其先序遍历序列。每两个数据之间留一个空格。

输入样例:
9
7 4 2 8 9 5 6 3 1 9
4 7 2 1 8 5 9 3 6
输出样例:
4 1 2 4 7 3 5 8 9 6
来源:
黄龙军, 等. 数据结构与算法(Python版),上海: 上海交通大学出版社, 2023. ISBN: 9787313280732

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB
 

#include<iostream>
using namespace std;
const int N = 20;
int a[N];
int b[N];
int res[N];
int t=0;
int max(int a,int b){
    return a>b?a:b;
}
int dfs(int l1,int r1,int l2,int r2){
    if(l1>r1)return 0;
    res[t++]=a[r1];
    int temp=0;
    for(int i=l2;i<=r2;i++){
        if(a[r1]==b[i]){
            temp=i;
            break;
        }
    }
    int a1 = dfs(l1,l1+temp-l2-1,l2,temp-1);
    int a2 = dfs(l1+temp-l2,r1-1,temp+1,r2);
    return max(a1,a2)+1;
}
int main()
{
    int n;
    while(cin>>n){
        t=0;
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<n;i++)cin>>b[i];
        printf("%d ",dfs(0,n-1,0,n-1));
        for(int i=0;i<t-1;i++)cout<<res[i]<<' ';
        cout<<res[t-1];
        cout<<endl;
    }
    return 0;
}

### 回答1: 根据后序遍历中序遍历序列,可以构造出二叉树。首先需要确定根节点,后序遍历的最后一个元素就是根节点,然后根据中序遍历的结果,可以将左子树和右子树的节点划分出来。然后对左子树和右子树递归进行构造。 举个例子,假设后序遍历序列为[9, 15, 7, 20, 3],中序遍历序列为[9, 3, 15, 20, 7],那么我们可以发现3是根节点,然后将中序遍历的结果分为左子树[9]和右子树[15, 20, 7]。接着,我们可以根据左子树和右子树的后序遍历序列[9]和[15, 7, 20],递归构造出左子树和右子树。 最终构造出的二叉树如下所示: ``` 3 / \ 9 20 / \ 15 7 ``` 在输出先序遍历序列时,遵循“根-左-右”的顺序。因此输出序列为[3, 9, 20, 15, 7]。 ### 回答2: 根据二叉树的遍历方式,中序遍历的顺序为:左子树、根节点、右子树;后序遍历的顺序为:左子树、右子树、根节点;先序遍历的顺序为:根节点、左子树、右子树。 根据后序中序遍历输出先序遍历,可以先从后序遍历确定根节点,再从中序遍历确定左右子树的节点个数,最后递归处理左右子树,输出先序遍历。 具体实现步骤如下: 1. 根据后序遍历的最后一个节点确定根节点。 2. 在中序遍历中找到根节点的位置,确定左子树和右子树的节点个数。 3. 递归地处理左子树,输出左子树的先序遍历。 4. 递归地处理右子树,输出右子树的先序遍历。 5. 最后输出根节点的值。 具体实现可以参考下面的代码: ```python def build_tree(in_order, post_order): if not post_order: return None root_val = post_order[-1] root = TreeNode(root_val) idx = in_order.index(root_val) left_in_order = in_order[:idx] right_in_order = in_order[idx+1:] left_post_order = post_order[:idx] right_post_order = post_order[idx:-1] root.left = build_tree(left_in_order, left_post_order) root.right = build_tree(right_in_order, right_post_order) return root def preorder_traversal(root): if root: print(root.val, end=' ') preorder_traversal(root.left) preorder_traversal(root.right) in_order = [4, 2, 5, 1, 6, 3, 7] post_order = [4, 5, 2, 6, 7, 3, 1] root = build_tree(in_order, post_order) preorder_traversal(root) # 输出 1 2 4 5 3 6 7 ``` 以上代码先定义了两个函数,分别用于构建二叉树和输出先序遍历。构建二叉树的过程跟“105. 从前序与中序遍历序列构造二叉树”类似,只是变成了根据后序中序遍历构建二叉树。输出先序遍历则是按照根节点、左子树、右子树的顺序输出节点值。 最后调用一下主函数即可得到输出结果。 ### 回答3: 对于一棵二叉树,可以通过先序遍历、中序遍历后序遍历之一来确定其结构。现在给定一棵二叉树后序遍历中序遍历,请输出其先序遍历。 首先,我们需要了解什么是先序遍历、中序遍历后序遍历。 先序遍历:按照“根-左-右”的顺序遍历整棵二叉树中序遍历:按照“左-根-右”的顺序遍历整棵二叉树后序遍历:按照“左-右-根”的顺序遍历整棵二叉树。 对于本题,我们需要根据给定后序遍历中序遍历,来确定二叉树的结构。 首先,我们可以通过后序遍历的最后一个元素来确定二叉树的根节点。 其次,我们可以利用中序遍历确定二叉树的左子树和右子树。具体来说,可以将中序遍历分为两个部分,分别是左子树和右子树。此时,我们可以根据左子树和右子树的元素数量,来确定左子树和右子树的范围。 最后,我们可以根据左子树和右子树的范围,来递归求解子树。具体来说,我们可以先递归求解右子树,再递归求解左子树。 举个例子,假设给定后序遍历中序遍历如下所示: 后序遍历:2 4 3 8 9 6 7 5 1 中序遍历:2 3 4 9 8 5 6 7 1 根据后序遍历,我们可以确定二叉树的根节点为1。 根据中序遍历,我们可以将其分为左子树和右子树。 左子树:2 3 4 右子树:9 8 5 6 7 此时,我们可以发现,左子树的元素数量为3,右子树的元素数量为5。因此,我们可以确定左子树的范围为后序遍历的倒数第6个元素到倒数第4个元素,右子树的范围为后序遍历的倒数第4个元素到倒数第1个元素。 接下来,我们可以先递归求解右子树,再递归求解左子树。 递归求解右子树时,根据后序遍历的倒数第1个元素可以确定其根节点为5。接着,根据中序遍历,可以将其分为左子树和右子树。 左子树:无 右子树:9 8 此时,我们可以发现,左子树的元素数量为0,右子树的元素数量为2。因此,我们可以确定左子树的范围为空,右子树的范围为后序遍历的倒数第3个元素到倒数第2个元素。 根据递归的方式,我们可以依次求解出右子树的先序遍历为:5 8 9。 接着,我们可以递归求解左子树。此时,根据后序遍历的倒数第7个元素可以确定其根节点为2。接着,根据中序遍历,可以将其分为左子树和右子树。 左子树:无 右子树:3 4 此时,我们可以发现,左子树的元素数量为0,右子树的元素数量为2。因此,我们可以确定左子树的范围为空,右子树的范围为后序遍历的倒数第6个元素到倒数第5个元素。 根据递归的方式,我们可以依次求解出左子树的先序遍历为:2 4 3。 最终,我们可以将右子树的先序遍历和左子树的先序遍历拼接起来,即可得到该二叉树的先序遍历为:1 5 8 9 2 4 3。 总结一下,我们可以通过以下三个步骤来求解二叉树的先序遍历: 1. 根据后序遍历的最后一个元素确定二叉树的根节点。 2. 根据中序遍历将其分为左子树和右子树,确定左子树和右子树的范围。 3. 递归求解左子树和右子树的先序遍历,然后将其拼接起来。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值