二叉树遍历基础

raw/articles/2026/05/二叉树遍历基础

一句话总结

二叉树只有 递归遍历层序遍历 这两种,再无其他。递归遍历可以衍生出 DFS 算法,层序遍历可以衍生出 BFS 算法。


核心内容

一、递归遍历(DFS)

1.1 遍历框架

递归遍历的核心是以下框架,遍历顺序固定(先左后右):

// 基本的二叉树节点
class TreeNode {
    int val;
    TreeNode left, right;
}

// 二叉树的递归遍历框架
void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    // 前序位置
    traverse(root.left);
    // 中序位置
    traverse(root.right);
    // 后序位置
}

关键理解

  • traverse 函数的遍历顺序:一直往左子节点走 → 遇到空指针 → 尝试往右 → 再往左 → 左右子树都完成 → 返回父节点
  • 遍历顺序(root 指针移动顺序)仅取决于左右子节点的递归调用顺序,与其他代码无关
  • 修改调用顺序(先右后左)会产生不同的遍历顺序,但一般不这样做

1.2 前序/中序/后序的本质

重要结论:递归遍历节点的顺序是固定的,但在不同位置写代码,效果不同

位置 执行时机 效果
前序位置 刚进入节点时执行(对子节点一无所知) 前序遍历结果 = root 指针移动顺序
中序位置 左子树遍历完成后,右子树遍历前执行 中序遍历结果 ≠ root 指针移动顺序
后序位置 左右子树都遍历完成后,即将离开节点时执行 后序遍历结果 ≠ root 指针移动顺序

可视化理解

  • 前序遍历:节点变绿的顺序(刚进入时)
  • 中序遍历:节点变蓝的顺序(左子树完成后)
  • 后序遍历:节点变红的顺序(左右子树都完成后)

1.3 关键性质


二、层序遍历(BFS)

层序遍历:一层一层地遍历二叉树,需要借助队列实现。

2.1 写法一:简单版

void levelOrderTraverse(TreeNode root) {
    if (root == null) {
        return;
    }
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);
    while (!q.isEmpty()) {
        TreeNode cur = q.poll();
        // 访问 cur 节点
        System.out.println(cur.val);

        // 把 cur 的左右子节点加入队列
        if (cur.left != null) {
            q.offer(cur.left);
        }
        if (cur.right != null) {
            q.offer(cur.right);
        }
    }
}

缺点:无法知道当前节点在第几层。

2.2 写法二:记录层数(最常用)

void levelOrderTraverse(TreeNode root) {
    if (root == null) {
        return;
    }
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);
    // 记录当前遍历到的层数(根节点视为第 1 层)
    int depth = 1;

    while (!q.isEmpty()) {
        int sz = q.size();  // 关键:必须在循环开始前保存队列长度
        for (int i = 0; i < sz; i++) {
            TreeNode cur = q.poll();
            // 访问 cur 节点,同时知道它所在的层数
            System.out.println("depth = " + depth + ", val = " + cur.val);

            if (cur.left != null) {
                q.offer(cur.left);
            }
            if (cur.right != null) {
                q.offer(cur.right);
            }
        }
        depth++;
    }
}

关键技巧

  • sz = q.size() 必须在 for 循环前保存,因为在循环过程中队列长度会变化
  • 可以用 while (sz-- > 0) 替代 for 循环
  • 这是最常用的层序遍历写法,可以解决"二叉树最小深度"等问题

2.3 写法三:带状态版(最灵活)

适用场景:每条树枝的权重可以是任意值(不只是 1),需要记录每个节点的路径权重和。

class State {
    TreeNode node;
    int depth;

    State(TreeNode node, int depth) {
        this.node = node;
        this.depth = depth;
    }
}

void levelOrderTraverse(TreeNode root) {
    if (root == null) {
        return;
    }
    Queue<State> q = new LinkedList<>();
    q.offer(new State(root, 1));

    while (!q.isEmpty()) {
        State cur = q.poll();
        // 访问 cur 节点,同时知道它的路径权重和
        System.out.println("depth = " + cur.depth + ", val = " + cur.node.val);

        if (cur.node.left != null) {
            q.offer(new State(cur.node.left, cur.depth + 1));
        }
        if (cur.node.right != null) {
            q.offer(new State(cur.node.right, cur.depth + 1));
        }
    }
}

应用场景

  • 多叉树的层序遍历
  • 图的 BFS 遍历
  • Dijkstra 算法
  • 边带有权重的场景

三、其他遍历?

核心结论:二叉树的遍历方式只有上面两种,其他写法都是表现形式上的差异:

表现形式 本质
用栈迭代遍历二叉树 本质是递归遍历,手动维护栈模拟递归调用
递归地一层层遍历 本质是层序遍历,把 for 循环用递归形式展现

与后续算法的关系

二叉树遍历 衍生算法 说明
递归遍历框架 DFS 算法、回溯算法 前中后序位置的思想延伸到深度优先搜索
层序遍历框架 BFS 算法 队列 + 层数记录延伸到广度优先搜索

相关概念

  • 二叉树 - 二叉树结构基础
  • 二叉搜索树 - BST 中序遍历有序性质
  • 队列 - 层序遍历依赖的数据结构
  • 递归 - 递归遍历的编程思想

Interactive Graph