二叉树——二叉树的中序遍历
题目:给定一个二叉树的根节点 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
List
dfs(root, res);
return res;
}
// 递归辅助方法:深度优先遍历
private void dfs(TreeNode root, List
// 递归终止条件:节点为空
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
List
// 用栈模拟递归调用
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;
}
}
代码说明
- 用栈存储待访问的节点,先一路向左遍历到底
- 弹出节点并记录值(访问根节点)
- 再转向右子树重复上述过程
- 优点:无递归栈溢出风险,效率稳定;缺点:代码稍复杂
List
功能几乎一模一样:
- 可以动态变长
- 尾部添加元素
- 用来存一串结果
为什么递归里不能每次都 new 一个 List 直接 return,否则数据一定会丢?
因为递归每调用一次,就会新开一个方法栈,
如果每次都新建列表,每个递归只返回自己那一小段结果,
根本合并不了,数据全散了。
结果是:永远拿不到数据!
为什么?
- 进入 dfs(1) → 创建 resA
- 进入 dfs(2) → 创建 resB
- 进入 dfs(null) 返回
- 把 2 加入 resB
- 回到 dfs(1)
- 把 1 加入 resA
- ……
最后:
- 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
3、赋值与null
int a;
a = null; // ❌ 报错,int 不能是 null
Integer b;
b = null; // ✅ 允许
二叉树里如果节点不存在,用null表示很正常,所以很多地方必须用Integer
二、什么是泛型集合?
泛型集合 = 带类型的容器
它规定:这个盒子只能装什么东西,不能乱装。
List
这里的
- List 是集合
就是泛型
合在一起就是:
泛型集合:只能存 Integer 类型的列表
三、泛型的作用:
- 规定这个集合只能存某一种类型
- 编译时就检查错误
- 取出来不用强转,安全又方便
为什么必须写List < Integer > 不能 List < int >?
因为:
泛型只支持引用类型(对象),不支持基本类型
- int → 基本类型 → 不能用在 <> 里
- Integer → 包装类、对象 → 可以用
所以你只能写:
List
List
- 泛型 = <类型> 这个尖括号语法
- 泛型集合 = 规定了只能装某种东西的集合
- 你写 List
= 这是个只能存整数的集合 - 因为泛型不支持基本类型 int,所以必须用 Integer
都是指定容器里装什么类型。
浙公网安备 33010602011771号