中序遍历

news/2025/3/29 5:28:56/文章来源:https://www.cnblogs.com/ohye/p/18790624

一、中序遍历概述

中序遍历(Inorder Traversal)是二叉树遍历的一种方式,遍历顺序为:左子树 -> 根节点 -> 右子树。这种遍历方式常用于二叉搜索树,可以得到一个升序排列的节点序列。

二、解决方式

第一种方法--递归实现

思路分析

  1. 递归终止条件:当前节点为null时返回
  2. 递归过程
    • 先递归遍历左子树
    • 访问当前节点(将值加入列表)
    • 再递归遍历右子树
  3. 特点:利用系统调用栈实现回溯,代码简洁易懂
    public List<Integer> inorderTraversal1(TreeNode root) {//使用递归方式,返回值是列表,所以需要列表存储,递归的思想是回溯,从叶子节点回溯,而终止条件就是叶子结点为空的时候,返回List<Integer> list = new ArrayList<>();//使用一个辅助方法来递归
        inoederHelper(root, list);return list;}private void inoederHelper(TreeNode current, List list){//终止条件if (current == null){return;}//遍历左子树
        inoederHelper(current.left, list);//得到回溯的节点,也就是第一个叶子结点,将当前结点添加到列表中
        list.add(current.val);//遍历右子树
        inoederHelper(current.right,list);}

时间复杂度

  • O(n),每个节点都会被访问一次

空间复杂度

 

  • 最坏情况下O(n)(树退化为链表时)
  • 平均情况下O(h),h为树的高度

第二种方法--迭代实现

思路分析

 

  1. 使用栈模拟递归:显式地使用栈来代替递归中的系统调用栈
  2. 算法步骤
    • 从根节点开始,将所有左子节点入栈
    • 弹出栈顶元素(最左节点)并访问
    • 转向该节点的右子树,重复上述过程
  3. 循环条件:当前节点不为空或栈不为空
    • 当前节点不为空:说明还有左子树需要处理
    • 栈不为空:说明还有节点需要访问
//使用迭代遍历,思想是利用栈先进后出的原则,从上到下迭代遍历,(从左节点开始)将当前结点入栈,当左子树遍历完后(左节点不为空),出栈,先出的就是左子树的叶子结点了//就可以实现中序遍历的思想,使用while循环,以栈是否为空判断退出循环。使用列表存储节点public List<Integer> inorderTraversal2(TreeNode root) {List<Integer> list = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();TreeNode current = root;while (current != null || !stack.isEmpty()){//遍历左子树while (current != null){stack.push(current);//入栈current = current.left;}//出栈current = stack.pop();list.add(current.val);//遍历右子树current = current.right;}return list;}

时间复杂度

  • O(n),每个节点都会被访问一次

空间复杂度

 

  • O(h),h为树的高度,栈的最大深度等于树的高度

 

测试用例

[1,null,2,3]

输出结果

[1,3,2]

[1,null,2,3]

[1,null,2,3]

 

# 中序遍历学习笔记
## 一、中序遍历概述
中序遍历(Inorder Traversal)是二叉树遍历的一种方式,遍历顺序为:左子树 -> 根节点 -> 右子树。这种遍历方式常用于二叉搜索树,可以得到一个升序排列的节点序列。
## 二、递归实现
### 代码实现```javapublic List<Integer> inorderTraversal1(TreeNode root) {    List<Integer> list = new ArrayList<>();    inoederHelper(root, list);    return list;}
private void inoederHelper(TreeNode current, List list) {    if (current == null) {        return;    }    inoederHelper(current.left, list);    list.add(current.val);    inoederHelper(current.right, list);}```
### 思路分析1. **递归终止条件**:当前节点为null时返回2. **递归过程**:   - 先递归遍历左子树   - 访问当前节点(将值加入列表)   - 再递归遍历右子树3. **特点**:利用系统调用栈实现回溯,代码简洁易懂
### 时间复杂度- O(n),每个节点都会被访问一次
### 空间复杂度- 最坏情况下O(n)(树退化为链表时)- 平均情况下O(h),h为树的高度
## 三、迭代实现
### 代码实现```javapublic List<Integer> inorderTraversal2(TreeNode root) {    List<Integer> list = new ArrayList<>();    Stack<TreeNode> stack = new Stack<>();    TreeNode current = root;        while (current != null || !stack.isEmpty()) {        while (current != null) {            stack.push(current);            current = current.left;        }        current = stack.pop();        list.add(current.val);        current = current.right;    }    return list;}```
### 思路分析1. **使用栈模拟递归**:显式地使用栈来代替递归中的系统调用栈2. **算法步骤**:   - 从根节点开始,将所有左子节点入栈   - 弹出栈顶元素(最左节点)并访问   - 转向该节点的右子树,重复上述过程3. **循环条件**:当前节点不为空或栈不为空   - 当前节点不为空:说明还有左子树需要处理   - 栈不为空:说明还有节点需要访问
### 时间复杂度- O(n),每个节点都会被访问一次
### 空间复杂度- O(h),h为树的高度,栈的最大深度等于树的高度
## 四、两种实现方式对比
| 特性        | 递归实现               | 迭代实现               ||-------------|-----------------------|-----------------------|| 代码复杂度  | 简单                  | 较复杂                || 空间复杂度  | 隐式系统栈,可能溢出  | 显式栈,更可控        || 适用场景    | 树深度不大时          | 树深度较大时          || 可读性      | 高                    | 中等                  |
## 五、测试用例验证
测试用例构建的二叉树结构:```        1       / \      2   3     / \   \    4   5   6           /          7```
预期中序遍历结果:`[4, 2, 5, 1, 7, 6, 3]`
两种实现方式均输出正确结果,验证了代码的正确性。
## 六、总结
1. 递归实现简洁直观,适合理解中序遍历的基本原理2. 迭代实现效率更高,适合处理深度较大的树3. 两种实现方式的核心思想相同:左-根-右的访问顺序4. 在实际应用中,可以根据具体情况选择合适的方法:   - 面试中通常要求掌握两种实现   - 实际项目中,树不大时可用递归,树很深时建议用迭代
## 七、可能的改进方向
1. 可以添加Morris遍历的实现,实现O(1)空间复杂度的中序遍历2. 对于迭代实现,可以增加对栈溢出异常的处理3. 可以扩展为通用的二叉树遍历模板,只需调整访问顺序即可实现前序、中序、后序遍历

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UML之包含用例

UML提供include机制避免用例重复,实现共享。本文介绍创建被包含用例的步骤,并通过实例展示其在基础用例共享、复杂用例分解及继承用例复用等场景下的应用。对于规模较大的用例,建模过程中经常会发现多个用例存在共享相同的子目标或子行为的情况。为避免重复并实现共享,UML提…

基于ESP32的物联网传感器和超声波距离传感器,Watmonitor可进行实时水位监测

Watmonitor是一个使用物联网传感器进行实时水位监测的自托管应用程序,具有多语言支持和易于访问的数据。Watmonitor是一个多功能的、自托管的web应用程序,专为实时水位监测而设计。使用基于ESP32的物联网传感器和超声波距离传感器,它可以跟踪各种环境中的水位,如水井,水箱…

【Java】【SpringBoot】Quartz——动态任务调度

回顾:前面学习了quartz的基础使用:https://www.cnblogs.com/luyj00436/p/18781141 定时任务可能是按照预设的时间进行。可是实际中,我们肯定希望自由的进行任务生成、暂停、恢复、删除、更新等操作。 Quartz本身没有提供动态调度的功能,需要自己根据相关的API开发。 场景订…

GrapeCity Documents V8.0 新版本特性

GcExcel V8.0 新版本特性丰富,包括:数据导入方面,可从多种数据源(如自定义对象、DataTable 等)导入,为 IRange.ImportData (..) 新增重载;假设分析上,通过 IWorksheet.Scenarios 接口支持 “方案” 功能,可进行多种操作且受保护工作表也能编辑;数据透视表能绑定表格数…

如何寻找替代FTP传输文件的软件,解决文件传输难题?

FTP因其操作简单、客户端种类多、价格低廉(甚至免费)等优势,受到众多企业的青睐,在全世界范围内得到广泛的应用。但它也面临着一些安全和效率方面的挑战,因此企业都在寻找可平滑替代FTP传输文件的软件。有以下局限性: 1.安全性弱:明文传输,漏洞频发,容易遭到DOS攻击;…

20244205 《Python程序设计》实验一报告

课程:《Python程序设计》 班级: 2442 姓名: 高赫 学号:20244205 实验教师:王志强 实验日期:2025年3月24日 必修/选修: 公选课 1.实验内容 (1).熟悉Python开发环境; (2).练习Python运行、调试技能; (3).编写程序,练习变量和类型、字符串、对象、缩进和注释等; (4).编…

微积分的本质——导数.18790288

本篇为3b1b系列【微积分的本质】笔记 原视频:02-导数的悖论 | 03-用几何来求导 | 04-直观理解链式法则和乘积法则定义导数 这是一个随着时间变化,车辆行驶距离的坐标图在横轴的任何一个点\(t\)上,如果你去查看车的车速表,上面都有一个数字表示当前的车速,但这是如何计算的…

推荐8款 .NET 开源、免费、实用的 Windows 效率软件

前言 今天大姚给大家推荐8款基于 .NET 开源、免费、实用的 Windows 效率软件,开发工作提升利器,希望可以帮助到有需要的小伙伴。 DevToys DevToys是一个专门为开发者设计的Windows工具箱,完全支持离线运行,无需使用许多不真实的网站来处理你的数据,常用功能有:格式化(支…

解密prompt系列51. R1实验的一些细节讨论

DeepSeek R1出来后业界都在争相复现R1的效果,这一章我们介绍两个复现项目SimpleRL和LogicRL,还有研究模型推理能力的Cognitive Behaviour,项目在复现R1的同时还针对R1训练策略中的几个关键点进行了讨论和消融实验,包括DeepSeek R1出来后业界都在争相复现R1的效果,这一章我…

读DAMA数据管理知识体系指南30文件和内容治理

读DAMA数据管理知识体系指南30文件和内容治理1. 方法 1.1. 诉讼应诉手册1.1.1. 电子取证工作一般在发生诉讼的时候进行1.1.2. 指引应明确电子取证的目标环境,并评估当前环境和目标环境之间是否存在差距1.1.3. 应记载电子取证活动生命周期的业务流程,明确电子取证团队的角色和…

为什么springboot的jar可以直接启动

一、讲述 1.SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包。 2.Spring Boot应用打包之后,生成一个Fat jar(jar包中包含jar),包含了应用依赖的jar包和Spring Boot loader相关的 类。 3.java -jar会去找jar中的manifest文件,在那里面找…