1. 项目概述:从“一笔画”到“树形搜索”的思维跃迁
最近在社区里看到一个挺有意思的问题:“一个7*5的格子,如何遍历所有格子一笔联通第二行左1格和第四行右1格”。这本质上是一个图的遍历问题,要求找到一条路径,不重复地访问所有节点(格子)。很多朋友的第一反应可能是尝试手动画线,或者用回溯算法去暴力搜索。但当我看到这个问题时,脑海里立刻浮现出的却是另一个更为基础、也更为强大的武器库: 二叉树的深度优先(DFS)与广度优先(BFS)遍历 。
你可能会疑惑,一个网格遍历问题,跟二叉树有什么关系?这正是我想分享的核心: 遍历的思维是相通的 。无论是二叉树、多叉树、图,还是这个7x5的网格,我们面对的核心挑战都是“如何系统性地、不重不漏地访问所有节点”。二叉树遍历,尤其是DFS和BFS,为我们提供了两种最经典、最根本的搜索“范式”或“策略”。理解了这两种范式,你就能举一反三,将其思想应用到链表遍历、文件系统递归搜索(比如那个 linux递归遍历文件夹并缩进输出 c程序 的需求)、甚至是JSON数据解析( gson jsonarray遍历取值 )等看似迥异的场景中。
简单来说,深度优先遍历像是一个执着“探险家”,认准一条路走到黑,直到尽头再回头;而广度优先遍历则像一个稳健“指挥官”,一层一层、稳扎稳打地推进。这两种策略,是解决“搜索二叉树”、“二叉树的非递归遍历”、“层序遍历”乃至更复杂图论问题的基石。本文将彻底拆解这两种遍历方式,不仅告诉你前序、中序、后序、层序遍历怎么写,更会深入探讨它们背后的思想、应用场景,以及如何将这种思想迁移到其他数据结构(如那个7x5网格)的问题解决中。无论你是正在学习数据结构的新手,还是想深化理解、应对面试中“关于二叉树前中后序遍历的常见问题”的老手,这篇文章都将带你从“会写代码”走向“懂其精髓”。
2. 二叉树遍历的核心思想与两种范式
在深入代码之前,我们必须先建立起清晰的认知模型。遍历二叉树,不是漫无目的地乱逛,而是有策略、有顺序地访问每个节点恰好一次。所有的策略都可以归结为两种最根本的范式:深度优先和广度优先。理解这两种范式,比死记硬背前中后序的代码重要得多。
2.1 深度优先遍历:深入腹地的探索者
深度优先遍历的核心思想是: 尽可能深地搜索树的分支 。当一条路走到尽头(遇到叶子节点)时,再回溯到上一个分岔口,选择另一条未探索的路径继续深入。这个过程天然地适合用 递归 来实现,因为递归的“调用栈”完美地模拟了回溯的行为。
我们可以用一个生活中的类比来理解:假设你要探索一个巨大的迷宫(二叉树),深度优先策略就像你在每个岔路口都选择最左边(或任意固定方向)的路一直走,并在墙上做标记。走到死胡同时,你退回上一个岔路口,选择另一条没标记过的路继续深入。你总是优先尝试走到迷宫的最深处。
在二叉树中,根据访问 根节点、左子树、右子树 这三者的顺序不同,深度优先遍历又分为三种具体形式:
- 前序遍历 :先访问根节点,再递归遍历左子树,最后递归遍历右子树。顺序是: 根 -> 左 -> 右 。想象成你第一次遇到一个岔路口(根),就先记录下这个路口的信息,然后再去探索左边的路,最后探索右边的路。
- 中序遍历 :先递归遍历左子树,再访问根节点,最后递归遍历右子树。顺序是: 左 -> 根 -> 右 。对于二叉搜索树,中序遍历的结果恰好是所有节点值的升序序列,这是它最重要的特性。
- 后序遍历 :先递归遍历左子树,再递归遍历右子树,最后访问根节点。顺序是: 左 -> 右 -> 根 。这种顺序在处理一些需要先处理子节点再处理父节点的问题时非常有用,例如计算子树的高度、释放树的内存等。
注意 :这里的“前”、“中”、“后”指的是 根节点 被访问的时机。这个定义是递归的,适用于树中的每一个子树。
2.2 广度优先遍历:层层推进的指挥官
广度优先遍历的核心思想是: 按距离根节点的层次,由近及远地访问节点 。它先访问根节点(第一层),然后访问根节点的所有子节点(第二层),接着是第二层节点的所有子节点(第三层),以此类推。这个过程很像水面的波纹,一圈一圈地扩散出去。
继续用迷宫的比喻:广度优先策略就像你站在迷宫起点,派出许多侦察兵。第一波侦察兵探索所有从起点直接可达的房间(第一层),并回报。然后你根据回报,命令每个房间里的侦察兵再探索他们房间直接可达的、且未被探索过的新房间(第二层)。你是一层一层地掌握整个迷宫的全貌。
在二叉树中,广度优先遍历通常被称为 层序遍历 。它没有像DFS那样的变体,顺序是唯一且确定的:从上到下,从左到右。
2.3 范式选择:何时用DFS,何时用BFS?
选择哪种遍历方式,取决于你要解决的问题:
- 需要处理子树或路径相关的问题 :通常用DFS。例如,寻找从根到叶子的某条路径、计算树的最大深度、判断树是否对称等。因为递归可以很自然地携带路径状态(通过函数参数)并处理子树。
- 需要按层次处理节点或找最短路径(在树中即最短深度) :必须用BFS。例如,打印树的每一层节点、找到距离根节点最近的叶子节点。因为BFS保证我们总是先访问深度更小的节点。
- 针对二叉搜索树 :中序遍历是王牌,可以以升序获取所有节点。
- 需要后序处理 :比如删除树、计算节点总数,后序遍历很方便,因为当你处理一个节点时,它的左右子树都已经被处理完了。
理解了这些思想,我们再看开头的“7x5网格一笔画”问题。你可以把每个格子看成图的一个节点,相邻格子有边
245



被折叠的 条评论
为什么被折叠?



