面试经典算法系列之二叉树7 -- 二叉树的中序遍历

面试经典算法22 - 二叉树的中序遍历

LeetCode.94
公众号:阿Q技术站

问题描述

给定一个二叉树的根节点 root ,返回 它的 中序 遍历

示例 1:

输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

提示:

  • 树中节点数目在范围 [0, 100]
  • -100 <= Node.val <= 100

思路

递归
  1. 如果根节点为空,返回空数组。
  2. 对根节点的左子树进行递归中序遍历,将结果存入结果数组。
  3. 将根节点的值存入结果数组。
  4. 对根节点的右子树进行递归中序遍历,将结果存入结果数组。
  5. 返回结果数组。
迭代
  1. 创建一个空数组 result 用于存储遍历结果。
  2. 创建一个辅助栈 st 用于存储遍历过程中的节点。
  3. 如果根节点为空,直接返回空数组。
  4. 从根节点开始,依次将左子节点入栈,直到左子节点为空。
  5. 弹出栈顶节点,将节点值加入结果数组,并将当前节点指向右子节点。
  6. 重复步骤 2 和步骤 3,直到栈为空且当前节点为空。

图解

这里还是给大家使用迭代法做一个图解。

  1. 先将头结点插入栈中。

image-20240229223447080

  1. 左节点不为空时,将左节点插入栈中,直至左节点遍历完。

image-20240229225012083

  1. 弹出栈顶元素,并添加至结果集。

image-20240229231315751

  1. 将根节点的右子节点添加进栈中。

image-20240229232732118

  1. 将右子节点的左子节点添加进栈中

image-20240229232902185

  1. 当前根节点(右子节点)的左子节点遍历完成,取出栈顶元素,并添加进结果集。

image-20240229233049675

  1. 继续将右子节点添加进栈中,直至遍历完。

image-20240229233211861

  1. 弹出栈顶元素,并添加进结果集。

image-20240229233306449

参考代码

C++
递归
#include <iostream>
#include <vector>

using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 递归中序遍历
void inorderTraversal(TreeNode* root, vector<int>& result) {
    if (root == nullptr) {
        return; // 如果节点为空,直接返回
    }
    inorderTraversal(root->left, result); // 递归遍历左子树
    result.push_back(root->val); // 将根节点的值加入结果数组
    inorderTraversal(root->right, result); // 递归遍历右子树
}

// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
    if (index >= nodes.size() || nodes[index] == -1) {
        return nullptr; // 如果节点为空,则返回nullptr
    }
    TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
    root->left = createTree(nodes, 2 * index + 1); // 创建左子树
    root->right = createTree(nodes, 2 * index + 2); // 创建右子树
    return root; // 返回当前节点
}

// 销毁二叉树
void destroyTree(TreeNode* root) {
    if (!root) return; // 如果根节点为空,直接返回
    destroyTree(root->left); // 递归销毁左子树
    destroyTree(root->right); // 递归销毁右子树
    delete root; // 删除当前节点
}

int main() {
    vector<int> nodes = {1, 2, 3, -1, -1, 4, 5}; // 定义二叉树的先序遍历序列
    TreeNode* root = createTree(nodes, 0); // 创建二叉树
    vector<int> result; // 存储遍历结果的数组
    inorderTraversal(root, result); // 进行递归中序遍历
    for (int val : result) { // 输出遍历结果
        cout << val << " ";
    }
    cout << endl;

    destroyTree(root); // 销毁二叉树

    return 0;
}
迭代
#include <iostream>
#include <vector>
#include <stack>

using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 中序遍历
vector<int> inorderTraversal(TreeNode* root) {
    vector<int> result; // 存储遍历结果的数组
    stack<TreeNode*> st; // 辅助栈,用于存储遍历过程中的节点

    while (root != nullptr || !st.empty()) {
        while (root != nullptr) { // 将左子节点入栈直到为空
            st.push(root);
            root = root->left;
        }
        root = st.top(); // 弹出栈顶节点
        st.pop();
        result.push_back(root->val); // 将节点值加入结果数组
        root = root->right; // 处理右子节点
    }

    return result; // 返回中序遍历结果数组
}

// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
    if (index >= nodes.size() || nodes[index] == -1) {
        return nullptr; // 如果节点为空,则返回nullptr
    }
    TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
    root->left = createTree(nodes, 2 * index + 1); // 创建左子树
    root->right = createTree(nodes, 2 * index + 2); // 创建右子树
    return root; // 返回当前节点
}

// 销毁二叉树
void destroyTree(TreeNode* root) {
    if (!root) return; // 如果根节点为空,直接返回
    destroyTree(root->left); // 递归销毁左子树
    destroyTree(root->right); // 递归销毁右子树
    delete root; // 删除当前节点
}

int main() {
    vector<int> nodes = {1, 2, 3, -1, -1, 4, 5}; // 定义二叉树的先序遍历序列
    TreeNode* root = createTree(nodes, 0); // 创建二叉树
    vector<int> result = inorderTraversal(root); // 进行中序遍历
    for (int val : result) { // 输出遍历结果
        cout << val << " ";
    }
    cout << endl;

    destroyTree(root); // 销毁二叉树

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

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

public class Solution {
    /**
     * 中序遍历二叉树
     * @param root 二叉树的根节点
     * @return 中序遍历结果
     */
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>(); // 存储遍历结果的列表
        Stack<TreeNode> stack = new Stack<>(); // 辅助栈,用于遍历过程中节点的存储
        TreeNode curr = root; // 当前节点

        while (curr != null || !stack.isEmpty()) {
            while (curr != null) { // 将左子节点入栈直到为空
                stack.push(curr);
                curr = curr.left;
            }
            curr = stack.pop(); // 弹出栈顶节点
            result.add(curr.val); // 将节点值加入结果列表
            curr = curr.right; // 处理右子节点
        }

        return result; // 返回中序遍历结果列表
    }

    public static void main(String[] args) {
        int[] nodes = {1, 2, 3, -1, -1, 4, 5}; // 二叉树的先序遍历序列
        TreeNode root = createTree(nodes, 0); // 创建二叉树
        Solution solution = new Solution();
        List<Integer> result = solution.inorderTraversal(root); // 进行中序遍历
        for (int val : result) { // 输出遍历结果
            System.out.print(val + " ");
        }
        System.out.println();
    }

    /**
     * 根据先序遍历序列创建二叉树
     * @param nodes 二叉树的先序遍历序列
     * @param index 当前节点在序列中的索引
     * @return 创建的二叉树的根节点
     */
    private static TreeNode createTree(int[] nodes, int index) {
        if (index >= nodes.length || nodes[index] == -1) {
            return null; // 如果节点为空,则返回null
        }
        TreeNode root = new TreeNode(nodes[index]); // 创建当前节点
        root.left = createTree(nodes, 2 * index + 1); // 创建左子树
        root.right = createTree(nodes, 2 * index + 2); // 创建右子树
        return root; // 返回当前节点
    }
}
Python
# 二叉树节点的定义
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def inorderTraversal(root):
    result = []  # 存储遍历结果的数组
    stack = []   # 辅助栈,用于存储遍历过程中的节点

    while root or stack:
        while root:  # 将左子节点入栈直到为空
            stack.append(root)
            root = root.left
        root = stack.pop()  # 弹出栈顶节点
        result.append(root.val)  # 将节点值加入结果数组
        root = root.right  # 处理右子节点

    return result  # 返回中序遍历结果数组

def createTree(nodes, index):
    if index >= len(nodes) or nodes[index] == -1:
        return None  # 如果节点为空,则返回None
    root = TreeNode(nodes[index])  # 创建当前节点
    root.left = createTree(nodes, 2 * index + 1)  # 创建左子树
    root.right = createTree(nodes, 2 * index + 2)  # 创建右子树
    return root  # 返回当前节点

def destroyTree(root):
    if not root:
        return  # 如果根节点为空,直接返回
    destroyTree(root.left)  # 递归销毁左子树
    destroyTree(root.right)  # 递归销毁右子树
    del root  # 删除当前节点

# 测试
nodes = [1, 2, 3, -1, -1, 4, 5]  # 定义二叉树的先序遍历序列
root = createTree(nodes, 0)  # 创建二叉树
result = inorderTraversal(root)  # 进行中序遍历
print(result)  # 输出遍历结果

destroyTree(root)  # 销毁二叉树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/544321.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【鸿蒙开发】第二十一章 Media媒体服务(二)--- 音频播放和录制

1 AVPlayer音频播放 使用AVPlayer可以实现端到端播放原始媒体资源&#xff0c;本开发指导将以完整地播放一首音乐作为示例&#xff0c;向开发者讲解AVPlayer音频播放相关功能。 以下指导仅介绍如何实现媒体资源播放&#xff0c;如果要实现后台播放或熄屏播放&#xff0c;需要…

稀碎从零算法笔记Day48-LeetCode:三角形最小路径和

题型&#xff1a;DP、二维DP、矩阵 链接&#xff1a;120. 三角形最小路径和 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的…

Project Euler_Problem 193_Few Repeated Digits_欧拉筛+容斥公式

解题思路&#xff1a;暴力搜索 代码&#xff1a; void solve() {ll i, j,k,x,y,z,p,q,u,v,l,l1;N 999966663333, NN 1024;//N 1000;double a, b, c,d;M.NT.get_prime_Euler(1000000);l M.NT.pcnt;for (i 1; i < l; i) {u M.NT.prime[i];v M.NT.prime[i 1];x u * …

交叉熵损失函数介绍

交叉熵是信息论中的一个重要概念&#xff0c;它的大小表示两个概率分布之间的差异&#xff0c;可以通过最小化交叉熵来得到目标概率分布的近似分布。 为了理解交叉熵&#xff0c;首先要了解下面这几个概念。 自信息 信息论的基本想法是&#xff0c;一个不太可能的事件发生了…

蓝桥杯:握手问题和小球反弹问题

试题 A: 握手问题 本题总分&#xff1a; 5 分 【问题描述】 小蓝组织了一场算法交流会议&#xff0c;总共有 50 人参加了本次会议。在会议上&#xff0c; 大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手&#xff08;且仅有一次&#x…

FRR-NET:用于弱光图像增强的快速重参数残差网络

很久之前写的文章&#xff0c;前两天才见刊。项目的具体代码因项目原因无法公布&#xff0c;我自己重新训练了一个版本&#xff08;包含两类预训练模型&#xff09;&#xff0c;供初学者参考。本文主要为AB式创新。 文章链接&#xff1a;paper 代码链接&#xff1a;GitHub || …

【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控件位置

往期回顾 【QT入门】 Qt自定义控件与样式设计之QSlider用法及qss-CSDN博客 【QT入门】Qt自定义控件与样式设计之qss的加载方式-CSDN博客 【QT入门】Qt自定义控件与样式设计之控件提升与自定义控件-CSDN博客 【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控…

【Unity】Feature has expired(H0041)

【背景】 在一台很久不用的电脑上更新了个人License&#xff0c;并导入了云项目&#xff0c;打开时却报错&#xff1a; 【分析】 网上查说要删缓存等等&#xff0c;试过都不行。重装Hub也不行。 这种环境类型的原因很难从信息入手定位错误。 所以我自己检查项目上有什么问题…

温故知新之-TCP Keepalive机制及长短连接

[学习记录] 前言 TCP连接一旦建立&#xff0c;只要连接双方不主动 close &#xff0c;连接就会一直保持。但建立连接的双方并不是一直都存在数据交互&#xff0c;所以在实际使用中会存在两种情况&#xff1a;一种是每次使用完&#xff0c;主动close&#xff0c;即短连接&…

ChatGPT 和 Elasticsearch:使用 Elastic 数据创建自定义 GPT

作者&#xff1a;Sandra Gonzales ChatGPT Plus 订阅者现在有机会创建他们自己的定制版 ChatGPT&#xff0c;称为 GPT&#xff0c;这替代了之前博客文章中讨论的插件。基于本系列的第一部分的基础 —— 我们深入探讨了在 Elastic Cloud 中设置 Elasticsearch 数据和创建向量嵌…

C语言100道练习题打卡(1)

1 有1&#xff0c;2&#xff0c;3&#xff0c;4四个数字&#xff0c;能组成多少个互不相同且不重复的三位数&#xff0c;都是多少 #include<stdio.h> //有1&#xff0c;2&#xff0c;3&#xff0c;4四个数字&#xff0c;能组成多少个互不相同且不重复的三位数&#xff…

Web端Excel的导入导出Demo

&#x1f4da;目录 &#x1f4da;简介:✨代码的构建&#xff1a;&#x1f4ad;Web端接口Excel操作&#x1f680;下载接口&#x1f680;导入读取数据接口 &#x1f3e1;本地Excel文件操作⚡导出数据&#x1f308;导入读取数据 &#x1f4da;简介: 使用阿里巴巴开源组件Easy Exce…

在Mac中打开终端的3种方法

在使用Mac时&#xff0c;有时需要深入研究设置&#xff0c;或者完成一些开发人员级的命令行任务。为此&#xff0c;你需要终端应用程序来访问macOS上的命令行。下面是如何启动它。 如何使用聚焦搜索打开终端 也许打开终端最简单、最快的方法是通过聚焦搜索。要启动聚焦搜索&a…

Collection与数据结构 二叉树(三):二叉树精选OJ例题(下)

1.二叉树的分层遍历 OJ链接 上面这道题是分层式的层序遍历,每一层有哪些结点都很明确,我们先想一想普通的层序遍历怎么做 /*** 层序遍历* param root*/public void levelOrder1(Node root){Queue<Node> queue new LinkedList<>();queue.offer(root);while (!qu…

支持向量机模型pytorch

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个支持向量机模型pytorch程序,最后打印5个条件分别的影响力。 示例一 支持向量机&#xff08;SVM&#xff09;是一种…

详解拷贝构造

拷贝构造的功能 写法&#xff1a; 拷贝构造函数的参数为什么是引用类型 系统自动生成的拷贝构造函数 拷贝构造的深拷贝与浅拷贝 概念 浅拷贝&#xff1a; 深拷贝 小结 拷贝构造的功能 拷贝构造函数可以把曾经实例化好的对象的数据拷贝给新创建的数据 &#xff0c;可见…

基于SpringBoot+Mybatis框架的私人影院预约系统(附源码,包含数据库文件)

基于SpringBootMybatis框架的私人影院预约系统&#xff0c;附源码&#xff0c;包含数据库文件。 非常完整的一个项目&#xff0c;希望能对大家有帮助哈。 本系统的完整源码以及数据库文件都在文章结尾处&#xff0c;大家自行获取即可。 项目简介 该项目设计了基于SpringBoo…

软考126-上午题-【软件工程】-测试方法

一、测试方法 在软件测试过程中&#xff0c;应该为定义软件测试模板&#xff0c;即将特定的测试方法和测试用例设计放在一系列的测试步骤中。 软件测试方法分为&#xff1a;静态测试和动态测试。 1-1、静态测试。 静态测试是指被测试程序不在机器上运行&#xff0c;而是采用…

事务隔离级别的无锁实现方式 -- MVCC

MVCC的全称是Multiversion Concurrency Control(多版本并发控制器)&#xff0c;是一种事务隔离级别的无锁的实现方式&#xff0c;用于提高事务的并发性能&#xff0c;即事务隔离级别的一种底层实现方式。 在了解MVCC之前&#xff0c;我们先来回顾一些简单的知识点&#xff1a;…

最优算法100例之47-从尾到头打印单链表

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 从尾到头打印单链表 题解报告 方法1:头插法逆置单链表然后依次打印;注意此处是不带头结点的单链表,带头节点的操作稍微有…