二叉树——二叉树的中序遍历

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

中序遍历的规则:左子树->根节点->右子树
以下提供两种最常用的实现方式:递归法迭代法

1、先定义二叉树节点类

public class TreeNode {

int val;
TreeNode left;
TreeNode right;
// 构造方法
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}

2、递归解法

递归是最简洁的写法,直接遵循左根右规则递归调用

import java.util.ArrayList;
import java.util.List;

class Solution {

// 主方法:返回中序遍历结果
public List inorderTraversal(TreeNode root) {
List res = new ArrayList<>();
dfs(root, res);
return res;
}

// 递归辅助方法:深度优先遍历
private void dfs(TreeNode root, List res) {
// 递归终止条件:节点为空
if (root == null) {
return;
}
// 1. 遍历左子树
dfs(root.left, res);
// 2. 访问根节点
res.add(root.val);
// 3. 遍历右子树
dfs(root.right, res);
}
}

代码说明

  • 终止条件:当前节点为 null 时直接返回
  • 执行顺序:严格按照** 左 → 根 → 右 **访问节点
  • 优点:代码极简,易理解;缺点:递归深度过大会栈溢出

3、迭代解法(非递归,推荐面试)

使用模拟递归过程,手动控制遍历顺序,是面试高频考点

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

class Solution {

public List inorderTraversal(TreeNode root) {
List res = new ArrayList<>();
// 用栈模拟递归调用
Stack stack = new Stack<>();
TreeNode cur = root;

// 循环条件:当前节点不为空 或 栈不为空
while (cur != null || !stack.isEmpty()) {
// 1. 一直遍历左子树,直到最左叶子节点
while (cur != null) {
stack.push(cur);
cur = cur.left;
}

// 2. 弹出栈顶节点(根节点),访问值
cur = stack.pop();
res.add(cur.val);

// 3. 遍历右子树
cur = cur.right;
}
return res;
}
}

代码说明

  1. 用栈存储待访问的节点,先一路向左遍历到底
  2. 弹出节点并记录值(访问根节点)
  3. 再转向右子树重复上述过程
  4. 优点:无递归栈溢出风险,效率稳定;缺点:代码稍复杂

List 等价于 C++ 的 vector,而不是普通数组。

功能几乎一模一样:

  • 可以动态变长
  • 尾部添加元素
  • 用来存一串结果

为什么递归里不能每次都 new 一个 List 直接 return,否则数据一定会丢?

因为递归每调用一次,就会新开一个方法栈,
如果每次都新建列表,每个递归只返回自己那一小段结果,
根本合并不了,数据全散了。

结果是:永远拿不到数据!
为什么?

  1. 进入 dfs(1) → 创建 resA
  2. 进入 dfs(2) → 创建 resB
  3. 进入 dfs(null) 返回
  4. 把 2 加入 resB
  5. 回到 dfs(1)
  6. 把 1 加入 resA
  7. ……

最后:

  • resB 里有 [2]
  • resA 里有 [1]
  • resC 里有 [3]

互相独立,谁也不认识谁,根本合并不了!
而且这些列表都是方法内部局部变量,
方法一结束,列表就消失了,外面完全拿不到。

一、int和Integer的区别?

  • int是基本类型:就是个纯数字,小、快、简单
  • Integer是包装类:是个对象,能存null,能用在集合里(List、Map)

1. 本质区别

int(基本数据类型)

  • 就是 C++ 里的 int
  • 存的是值本身
  • 默认值:0
  • 不能为 null
  • 不能放进 List 这种泛型集合里

Integer(包装类 / 对象)

  • 是 int 的包装类,本质是个对象
  • 存的是引用
  • 默认值:null
  • 可以为 null
  • 只有它能放进 List

2、为什么 List 只能用 Integer,不能用 int?

泛型集合里必须方对象,不能放基本类型。

  • List ❌ 报错
  • List ✅ 正确

就跟 C++ 里 vector 可以,但 Java 泛型不支持基本类型,必须用包装类。

3、赋值与null
int a;
a = null; // ❌ 报错,int 不能是 null

Integer b;
b = null; // ✅ 允许

二叉树里如果节点不存在,用null表示很正常,所以很多地方必须用Integer

二、什么是泛型集合?

泛型集合 = 带类型的容器
它规定:这个盒子只能装什么东西,不能乱装。

List res = new ArrayList<>();
这里的

  • List 是集合
  • 就是泛型
    合在一起就是:

泛型集合:只能存 Integer 类型的列表

三、泛型的作用:

  • 规定这个集合只能存某一种类型
  • 编译时就检查错误
  • 取出来不用强转,安全又方便

为什么必须写List < Integer > 不能 List < int >?

因为:
泛型只支持引用类型(对象),不支持基本类型

  • int → 基本类型 → 不能用在 <> 里
  • Integer → 包装类、对象 → 可以用

所以你只能写:
List
List

  • 泛型 = <类型> 这个尖括号语法
  • 泛型集合 = 规定了只能装某种东西的集合
  • 你写 List = 这是个只能存整数的集合
  • 因为泛型不支持基本类型 int,所以必须用 Integer

就相当于 vector 后面的
都是指定容器里装什么类型。

posted @ 2026-04-12 11:14  ZealousMclaren  阅读(29)  评论(0)    收藏  举报