哪吒教你用“乾坤圈”搞定二叉树的层次遍历!
大家好,我是哪吒!今天咱们不闹海,也不打妖怪,来聊聊二叉树的层次遍历。你可能要问了:“哪吒,你不是玩乾坤圈和混天绫的吗?怎么搞起算法来了?”嘿嘿,别急,听我慢慢道来。其实,算法和法宝一样,都是解决问题的利器。今天我就用我的“乾坤圈”带你搞定二叉树的层次遍历!
什么是层次遍历?
层次遍历,顾名思义,就是一层一层地遍历二叉树。比如下面这棵树:
复制
1
/ \
2 3
/ \ \
4 5 6
层次遍历的结果就是:[[1], [2, 3], [4, 5, 6]]。是不是很简单?但问题来了,怎么用代码实现呢?
递归 vs 非递归
很多人一看到树,就想用递归。递归确实简单,但今天咱们不走寻常路,用非递归的方式来实现层次遍历。为什么?因为递归虽然优雅,但容易“爆栈”(栈溢出),尤其是当树很深的时候。非递归方式虽然写起来复杂一点,但更稳健,适合处理大规模数据。
非递归实现思路
非递归实现层次遍历的核心思想是:用队列来辅助。队列是什么?你可以把它想象成一个“乾坤圈”,先进先出,先来的先处理。具体步骤如下:
-
初始化:把根节点放进队列。
-
循环处理:
- 每次从队列中取出当前层的所有节点,把它们的值存到一个列表中。
- 把这些节点的子节点(左孩子和右孩子)放进队列,准备下一轮处理。
-
结束条件:当队列为空时,说明所有节点都处理完了。
是不是很简单?接下来,咱们用代码来实现这个逻辑。
Java 代码实现
public List<List<Integer>> levelOrder(TreeNode root) {
// 如果根节点为空,直接返回空列表
if (root == null) {
return new ArrayList<>();
}
// 结果列表,存储每一层的节点值
List<List<Integer>> res = new ArrayList<>();
// 队列,用于辅助层次遍历
Queue<TreeNode> queue = new ArrayDeque<>();
queue.offer(root); // 把根节点放进队列
// 开始遍历
while (!queue.isEmpty()) {
// 当前层的节点数量
int n = queue.size();
// 存储当前层的节点值
List<Integer> list = new ArrayList<>(n);
// 遍历当前层的所有节点
for (int i = 0; i < n; i++) {
TreeNode node = queue.poll(); // 取出队头节点
list.add(node.val); // 把节点值加入列表
// 把左孩子和右孩子放进队列
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
// 把当前层的节点值列表加入结果
res.add(list);
}
return res;
}
C++ 代码实现
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
// 如果根节点为空,直接返回空列表
if (root == nullptr) {
return res;
}
// 队列,用于辅助层次遍历
queue<TreeNode*> queue;
queue.push(root); // 把根节点放进队列
// 开始遍历
while (!queue.empty()) {
// 当前层的节点数量
int size = queue.size();
// 存储当前层的节点值
vector<int> vec;
// 遍历当前层的所有节点
for (int i = 0; i < size; i++) {
auto node = queue.front(); // 取出队头节点
queue.pop(); // 弹出队头节点
vec.push_back(node->val); // 把节点值加入列表
// 把左孩子和右孩子放进队列
if (node->left != nullptr) {
queue.push(node->left);
}
if (node->right != nullptr) {
queue.push(node->right);
}
}
// 把当前层的节点值列表加入结果
res.push_back(vec);
}
return res;
}
代码解析
- 队列的作用:队列就像一个“乾坤圈”,帮助我们按层次顺序处理节点。每次处理一层,把下一层的节点放进队列。
- 时间复杂度:每个节点都会被访问一次,所以时间复杂度是 O(n),其中 n 是节点数量。
- 空间复杂度:队列的最大长度是二叉树最宽的那一层,所以空间复杂度是 O(m),其中 m 是二叉树的最大宽度。
为什么坚持非递归?
你可能要问了:“哪吒,递归不是更简单吗?为什么要用非递归?”其实,非递归方式虽然写起来复杂一点,但它有两个优点:
- 避免栈溢出:递归调用会占用栈空间,如果树很深,容易导致栈溢出。
- 更直观:非递归方式更贴近计算机的执行逻辑,适合处理大规模数据。
就像我哪吒,虽然用乾坤圈打妖怪很爽,但有时候也得用混天绫,灵活应对各种情况!
总结
今天咱们用“乾坤圈”(队列)搞定了二叉树的层次遍历。通过非递归的方式,我们不仅避免了栈溢出的风险,还更深入地理解了层次遍历的本质。希望这篇文章能让你对二叉树遍历有新的认识,也希望大家在算法的道路上坚持不懈,像我哪吒一样,勇往直前!
最后,如果你觉得这篇文章有用,别忘了点赞、分享哦!咱们下次再见,继续用“乾坤圈”搞定更多算法难题!