跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

二叉树前中后序遍历详解:递归与迭代实现

二叉树遍历涵盖前序、中序、后序三种模式,是数据结构基础重点。文章详细解析了每种遍历的递归实现逻辑,并重点对比了迭代方案。其中前序迭代利用栈模拟调用顺序,中序迭代通过左子树入栈回溯根节点,后序迭代则提供基于 prev 指针标记和反转前序结果两种技巧。内容包含完整 Java 代码示例及复杂度分析,适合巩固算法基础。

神经兮兮发布于 2026/3/21更新于 2026/7/555 浏览
二叉树前中后序遍历详解:递归与迭代实现

二叉树前中后序遍历详解

二叉树是数据结构中的核心结构之一,其遍历方式是理解树形算法的基础。本文将深入解析前序、中序、后序三种遍历模式,分别展示递归与迭代的实现细节,并对比不同方案的优劣。

一、二叉树的前序遍历

前序遍历遵循「根节点 → 左子树 → 右子树」的访问顺序。

1. 递归写法

递归是最直观的解法,直接映射遍历定义。核心在于先处理当前节点,再依次递归左右子树。

实现逻辑:

  • 终止条件:节点为空时返回。
  • 访问当前:将节点值加入结果列表。
  • 递归左子树:继续向左深入。
  • 递归右子树:最后处理右侧分支。
/**
 * Definition for a binary tree node.
 * 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;
 *     }
 * }
 */
class Solution {
    private List<Integer> list = new ArrayList<>();

    public List<Integer> preorderTraversal(TreeNode root) {
        find(root);
        return list;
    }

    private void find(TreeNode node) {
        if (node != null) {
            list.add(node.val);
            find(node.left);
            find(node.right);
        }
    }
}

时间复杂度为 O(n),空间复杂度取决于递归栈深度,最坏为 O(n)。

2. 迭代写法

迭代法利用栈模拟系统调用栈。由于栈是后进先出(LIFO),为了优先访问左子树,我们需要先将右子树入栈,再将左子树入栈。

关键步骤:

  1. 初始化栈,将根节点压入。
  2. 循环弹出栈顶节点,记录值。
  3. 先压入右子节点,再压入左子节点。
  4. 重复直至栈空。
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
         (root == )  list;
        Deque<TreeNode> stack =  <>();
        stack.push(root);
         (!stack.isEmpty()) {
               stack.pop();
             (node == ) ;
            list.add(node.val);
            stack.push(node.right);
            stack.push(node.left);
        }
         list;
    }
}
if
null
return
new
LinkedList
while
TreeNode
node
=
if
null
continue
return

此方法避免了递归可能导致的栈溢出风险,适合处理深层树结构。

二、二叉树的中序遍历

中序遍历遵循「左子树 → 根节点 → 右子树」的顺序,常用于获取有序序列。

1. 递归写法

逻辑简单:先递归左子树,再访问根,最后递归右子树。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) return list;
        inOrder(root, list);
        return list;
    }

    public void inOrder(TreeNode root, List<Integer> list) {
        if (root == null) return;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }
}

2. 迭代写法

迭代的核心在于「一路向左」,直到无法继续,此时栈顶即为当前应访问的根节点。

流程解析:

  • 外层循环控制整体进度(栈非空或当前节点不为空)。
  • 内层循环持续将左子节点入栈,直到 null。
  • 弹出栈顶节点(此时左子树已遍历完),记录值。
  • 转向右子节点,重复上述过程。
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) return list;
        Deque<TreeNode> stack = new LinkedList<>();
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            list.add(root.val);
            root = root.right;
        }
        return list;
    }
}

三、二叉树的后序遍历

后序遍历遵循「左子树 → 右子树 → 根节点」,难点在于根节点必须在左右子树之后访问。

1. 递归写法

标准递归逻辑:先左,再右,最后根。

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) return list;
        postOrder(root, list);
        return list;
    }

    public void postOrder(TreeNode root, List<Integer> list) {
        if (root == null) return;
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.add(root.val);
    }
}

2. 迭代写法 1:标记法

单纯用栈难以区分「首次访问」和「子树处理完毕」。引入 pre 指针记录上一个访问的节点,判断右子树是否已处理。

逻辑要点:

  • 若右子树为空或已被访问(pre == node.right),说明左右已完成,可访问根。
  • 否则,转向右子树继续遍历。
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) return list;
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode pre = null;
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            TreeNode node = stack.peek();
            if (node.right == null || pre == node.right) {
                list.add(stack.pop().val);
                pre = node;
                root = null;
            } else {
                root = node.right;
            }
        }
        return list;
    }
}

3. 迭代写法 2:反转前序

观察规律:前序是「根→左→右」,后序是「左→右→根」。若调整为「根→右→左」遍历,结果翻转即得后序。

实现技巧:

  • 模仿前序遍历,但入栈顺序改为先左后右(确保右先出栈)。
  • 遍历结束后,对结果列表执行 Collections.reverse()。
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) return list;
        Deque<TreeNode> stack = new LinkedList<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            list.add(node.val);
            if (node.left != null) stack.push(node.left);
            if (node.right != null) stack.push(node.right);
        }
        Collections.reverse(list);
        return list;
    }
}

该方案代码简洁,易于记忆,是面试中的高频考点。

目录

  1. 二叉树前中后序遍历详解
  2. 一、二叉树的前序遍历
  3. 1. 递归写法
  4. 2. 迭代写法
  5. 二、二叉树的中序遍历
  6. 1. 递归写法
  7. 2. 迭代写法
  8. 三、二叉树的后序遍历
  9. 1. 递归写法
  10. 2. 迭代写法 1:标记法
  11. 3. 迭代写法 2:反转前序
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 程序员转行大模型领域:热门岗位与学习路径解析
  • GESP 2025 年 12 月 C++ 七级认证真题与解析(单选题 1-7)
  • 【Copy Web独立开发者实战:我是如何用 AI 实现网页 UI 1:1 完美复刻的?】
  • C++ 哈希表封装:模拟实现 unordered_map 和 unordered_set
  • Android 技术体系化进阶指南:从基础到架构的全方位解析
  • 大语言模型学习路线:从基础理论到项目实战
  • 数据结构基础:二叉树与堆的实现详解
  • 基于 SpringBoot2+Vue3 的旅游出行指南系统设计与实现
  • 纯 CSS 实现 3D 文字效果实战教程
  • GpuGeek 平台:AI 开发者与中小企业的算力解决方案
  • 深入理解 C++ 异常机制
  • 前端程序员转行大模型开发指南
  • FPGA 实现 CAN 总线原理与 Verilog 代码详解
  • 大模型 + 数据分析产品打造指南:核心步骤与成功策略
  • 实时数据处理:Kafka与Python构建高可靠流处理系统
  • Python 实现 Markdown 转 Word(docx)文档转换方案
  • DeepSeek-R1 大模型基于 MS-Swift 框架的部署、推理与微调实践
  • cargo-asm 插件开发指南:为 Rust 项目贡献新功能
  • C++ 语言基础与进阶教程
  • 基于若依框架的 SpringBoot+Vue3 前后端分离项目搭建与代码生成教程

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online