首页 > 其他分享 >【题解 | 二叉树】给定二叉树的后序遍历和中序遍历,求层序遍历结果

【题解 | 二叉树】给定二叉树的后序遍历和中序遍历,求层序遍历结果

时间:2024-04-09 20:00:33浏览次数:32  
标签:结点 遍历 TreeNode int 题解 二叉树 inOrder postOrder

树的遍历

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数 N ( ≤ 30 ) N(≤30) N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2

解题

在后序遍历序列中,根节点总是在最后一个位置,而在中序遍历序列中,根节点将序列分为左右两部分,分别对应左子树和右子树。

因此,我们可以利用两个数组的信息,递归构建二叉树,然后再进行层序遍历。

Java

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;

// 结点类
class TreeNode {
    int val;			// 值
    TreeNode left;		// 左孩子
    TreeNode right;		// 右孩子

    TreeNode(int x) {
        val = x;
    }
}

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int[] postOrder = new int[N];
        int[] inOrder = new int[N];
        for (int i = 0; i < N; i++) {
            postOrder[i] = scanner.nextInt();
        }
        for (int i = 0; i < N; i++) {
            inOrder[i] = scanner.nextInt();
        }
        // 根据后序遍历结果和前序遍历结果,构建二叉树
        TreeNode root = helper(postOrder, inOrder);
        // 层序遍历
        List<Integer> ans = levelOrderTraversal(root);
        // 输出结果
        for (int i = 0; i < ans.size(); i++) {
            System.out.print(ans.get(i));
            if (i < ans.size() - 1) {
                System.out.print(" ");
            }
        }
        scanner.close();
    }

    // 检查是否有某个序列为空
    private static TreeNode helper(int[] postOrder, int[] inOrder) {
        if (postOrder == null || inOrder == null || postOrder.length == 0 || inOrder.length == 0) {
            return null;
        }
        return buildTree(postOrder, 0, postOrder.length - 1, inOrder, 0, inOrder.length - 1);
    }

    /**
     * 构建二叉树
     * @param postOrder 	后序遍历结果
     * @param postStart 	后序遍历序列的起始位置
     * @param postEnd 		后序遍历序列的结束位置
     * @param inOrder 		中序遍历结果
     * @param inStart 		中序遍历序列的起始位置
     * @param inEnd 		中序遍历序列的结束位置
     * @return 构建的二叉树的根节点
     */
    private static TreeNode buildTree(int[] postOrder, int postStart, int postEnd, int[] inOrder, int inStart, int inEnd) {
    	// (0) 终止条件:此时没有结点了,返回空树
        if (postStart > postEnd || inStart > inEnd) {
            return null;
        }

        // (1) 先找到根结点:后序遍历的最后一个结点
        int rootVal = postOrder[postEnd];
        TreeNode root = new TreeNode(rootVal);

        // (2) 在中序遍历序列中找到根结点的位置
        int rootIndexInInOrder = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inOrder[i] == rootVal) {
                rootIndexInInOrder = i;
                break;
            }
        }

        // (3) 计算左子树的结点个数
        int leftTreeSize = rootIndexInInOrder - inStart;
        
        // (4) 递归构建左子树和右子树
        root.left = buildTree(postOrder, postStart, postStart + leftTreeSize - 1, inOrder, inStart, rootIndexInInOrder - 1);
        root.right = buildTree(postOrder, postStart + leftTreeSize, postEnd - 1, inOrder, rootIndexInInOrder + 1, inEnd);

        // (5) 返回根结点
        return root;
    }

    // 层序遍历二叉树
    private static List<Integer> levelOrderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }

        // 创建队列,用于层序遍历
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        // 循环遍历队列中的结点
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            // 将当前结点的值加入结果列表
            result.add(node.val);
            if (node.left != null) {
                queue.offer(node.left); // 将左子结点加入队列
            }
            if (node.right != null) {
                queue.offer(node.right); // 将右子结点加入队列
            }
        }

        return result;
    }
}

C++

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 结点类
class TreeNode {
public:
    int val;        // 值
    TreeNode *left;     // 左孩子
    TreeNode *right;    // 右孩子

    TreeNode(int x) {
        val = x;
        left = nullptr;
        right = nullptr;
    }
};

// 构建二叉树
TreeNode* buildTree(vector<int>& postOrder, int postStart, int postEnd, vector<int>& inOrder, int inStart, int inEnd) {
    // 终止条件:此时没有结点了,返回空树
    if (postStart > postEnd || inStart > inEnd) {
        return nullptr;
    }

    // 先找到根结点:后序遍历的最后一个结点
    int rootVal = postOrder[postEnd];
    TreeNode* root = new TreeNode(rootVal);

    // 在中序遍历序列中找到根结点的位置
    int rootIndexInInOrder = 0;
    for (int i = inStart; i <= inEnd; i++) {
        if (inOrder[i] == rootVal) {
            rootIndexInInOrder = i;
            break;
        }
    }

    // 计算左子树的结点个数
    int leftTreeSize = rootIndexInInOrder - inStart;
    
    // 递归构建左子树和右子树
    root->left = buildTree(postOrder, postStart, postStart + leftTreeSize - 1, inOrder, inStart, rootIndexInInOrder - 1);
    root->right = buildTree(postOrder, postStart + leftTreeSize, postEnd - 1, inOrder, rootIndexInInOrder + 1, inEnd);

    // 返回根结点
    return root;
}

// 层序遍历二叉树
vector<int> levelOrderTraversal(TreeNode* root) {
    vector<int> result;
    if (root == nullptr) {
        return result;
    }

    // 创建队列,用于层序遍历
    queue<TreeNode*> q;
    q.push(root);

    // 循环遍历队列中的结点
    while (!q.empty()) {
        TreeNode* node = q.front();
        q.pop();
        // 将当前结点的值加入结果列表
        result.push_back(node->val);
        if (node->left != nullptr) {
            q.push(node->left); // 将左子结点加入队列
        }
        if (node->right != nullptr) {
            q.push(node->right); // 将右子结点加入队列
        }
    }

    return result;
}

int main() {
    int N;
    cin >> N;
    vector<int> postOrder(N);
    vector<int> inOrder(N);
    for (int i = 0; i < N; i++) {
        cin >> postOrder[i];
    }
    for (int i = 0; i < N; i++) {
        cin >> inOrder[i];
    }

    // 根据后序遍历结果和中序遍历结果,构建二叉树
    TreeNode* root = buildTree(postOrder, 0, N - 1, inOrder, 0, N - 1);
    // 层序遍历
    vector<int> ans = levelOrderTraversal(root);
    // 输出结果
    for (int i = 0; i < ans.size(); i++) {
        cout << ans[i];
        if (i < ans.size() - 1) {
            cout << " ";
        }
    }

    return 0;
}

测试链接:L2-006 树的遍历

标签:结点,遍历,TreeNode,int,题解,二叉树,inOrder,postOrder
From: https://blog.csdn.net/m0_62999278/article/details/137557558

相关文章

  • Codeforces Round 938 (Div. 3)题解(A-E)
    A.YogurtSale题意:输入一份酸奶a元,两份b元,求买n份酸奶最少要多少钱。#include<iostream>#include<string>#include<cstring>#include<algorithm>usingnamespacestd;typedeflonglongll;constintN=1e6+7;voidsolve(){ intn,a,b;cin>>n>>......
  • ARC080F Prime Flip 题解
    传送门题意:给定初始\(a\)数组,每次可以选一个长度为奇质数的区间取反。问全变成\(0\)要多少次操作。和Password、XorReplace的套路相同,做一个差分。令\(b_i=a_i\xora_{i-1}\),目的就是让\(b\)数组变为全\(0\)。对\(a_i\sima_{i+p-1}\)取反相当于对\(b_i,b_{i+p......
  • 题解:P10234 [yLCPC2024] B. 找机厅
    题意简述给你一个长\(n\)宽\(m\)的\(01\)迷宫,从\((1,1)\)开始要走到\((n,m)\)。如果能走那么输出最短路和路径(路径用\(LRUD\)表示),否则输出\(-1\)。有\(t\)组数据。如果当前格子是\(0\)那么你只能走到\(1\)的格子,反之亦然。思路考虑使用\(BFS\),每次走......
  • 顺序表的建立与遍历
    读入n值及n个整数,建立顺序表并遍历输出。输入格式:读入n及n个整数输出格式:输出n个整数,以空格分隔(最后一个数的后面没有空格)。首先定义顺序表这个结构体点击查看代码typedefstructsqList{intarrayList[maxSize];intarrayLength;}需要初始化一个顺序表点......
  • java 对List<Map<String, Object>>遍历
    在Java中,遍历List<Map<String,Object>>可以通过多种方式来实现。以下是一些常见的方法:使用for-each循环javaList<Map<String,Object>>list=//初始化你的Listfor(Map<String,Object>map:list){for(Map.Entry<String,Object>entry:map.entrySet()){......
  • 20天【代码随想录算法训练营34期】第六章 二叉树part07 ( ● 530.二叉搜索树的最小绝对
    530.二叉搜索树的最小绝对差#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:deftraversal(self,......
  • java 对Map<String, Object>遍历
    在Java中,你可以使用多种方法来遍历Map<String,Object>。以下是一些常见的方法:使用Map.Entry和IteratorjavaMap<String,Object>map=newHashMap<>();//添加一些键值对到map中Iterator<Map.Entry<String,Object>>iterator=map.entrySet().iterator();while(iterator.ha......
  • 数据结构--二叉树
    1.树的概念树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。如果将他的图画出来的话很像一棵树。1.1名词概念根结点:没有父结点(前驱节点)的结点;如上方A就是根结点父结点或双亲结点:如果这个结点下方还有结点(孩子节点)那么称这个结点为下方结点......
  • AtCoder Beginner Contest 348 A-F 题解
    A-PenaltyKickQuestion高桥将在一场足球比赛中获得\(N\)个点球。对于第\(i\)个罚球,如果\(i\)是\(3\)的倍数,他将罚球失败,否则罚球成功。请打印他罚球的结果。Solution当\(i\%3==0\)时说明能被\(3\)整除Code#include<bits/stdc++.h>usingnamespacest......
  • SP30785的题解
    (一)树链剖分板子题。支持单点取反,区间查询。在线段树的每一个节点上分别记录全为\(1\)或全为\(0\)。代码挺好理解的。(二)AC代码。#include<bits/stdc++.h>usingnamespacestd;constintmxn=3e5+10;intn,q,head[mxn],cnt,id[mxn],cntt,fa[mxn],cnt1,son[mxn],siz[m......