二叉树遍历
实现二叉树的前序、中序、后序和层序遍历
问题
实现二叉树的四种遍历方式:前序、中序、后序、层序。
解答
二叉树节点定义
class TreeNode {
constructor(val) {
this.val = val;
this.left = null;
this.right = null;
}
}
前序遍历(根 → 左 → 右)
// 递归
function preorderRecursive(root) {
const result = [];
function traverse(node) {
if (!node) return;
result.push(node.val); // 先访问根
traverse(node.left); // 再访问左子树
traverse(node.right); // 最后访问右子树
}
traverse(root);
return result;
}
// 迭代
function preorderIterative(root) {
if (!root) return [];
const result = [];
const stack = [root];
while (stack.length) {
const node = stack.pop();
result.push(node.val);
// 先压右再压左,出栈时就是先左后右
if (node.right) stack.push(node.right);
if (node.left) stack.push(node.left);
}
return result;
}
中序遍历(左 → 根 → 右)
// 递归
function inorderRecursive(root) {
const result = [];
function traverse(node) {
if (!node) return;
traverse(node.left); // 先访问左子树
result.push(node.val); // 再访问根
traverse(node.right); // 最后访问右子树
}
traverse(root);
return result;
}
// 迭代
function inorderIterative(root) {
const result = [];
const stack = [];
let current = root;
while (current || stack.length) {
// 一直往左走到底
while (current) {
stack.push(current);
current = current.left;
}
// 弹出节点,访问它
current = stack.pop();
result.push(current.val);
// 转向右子树
current = current.right;
}
return result;
}
后序遍历(左 → 右 → 根)
// 递归
function postorderRecursive(root) {
const result = [];
function traverse(node) {
if (!node) return;
traverse(node.left); // 先访问左子树
traverse(node.right); // 再访问右子树
result.push(node.val); // 最后访问根
}
traverse(root);
return result;
}
// 迭代(前序的变体:根右左 → 反转得到左右根)
function postorderIterative(root) {
if (!root) return [];
const result = [];
const stack = [root];
while (stack.length) {
const node = stack.pop();
result.push(node.val);
// 先压左再压右,出栈顺序是根右左
if (node.left) stack.push(node.left);
if (node.right) stack.push(node.right);
}
return result.reverse(); // 反转得到左右根
}
层序遍历(BFS)
function levelOrder(root) {
if (!root) return [];
const result = [];
const queue = [root];
while (queue.length) {
const levelSize = queue.length;
const currentLevel = [];
// 处理当前层的所有节点
for (let i = 0; i < levelSize; i++) {
const node = queue.shift();
currentLevel.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
result.push(currentLevel);
}
return result;
}
测试
// 1
// / \
// 2 3
// / \
// 4 5
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
console.log(preorderRecursive(root)); // [1, 2, 4, 5, 3]
console.log(inorderRecursive(root)); // [4, 2, 5, 1, 3]
console.log(postorderRecursive(root)); // [4, 5, 2, 3, 1]
console.log(levelOrder(root)); // [[1], [2, 3], [4, 5]]
关键点
- 前/中/后序的区别在于根节点的访问时机:前序先访问根,中序中间访问根,后序最后访问根
- 递归写法简单直观,但有栈溢出风险;迭代用显式栈模拟递归过程
- 层序遍历用队列实现 BFS,记录每层节点数来区分层级
- 后序迭代可以用前序变体(根右左)再反转得到
- 中序遍历的迭代写法需要先一路向左,再回溯处理右子树
目录