← 树 · 遍历、平衡 BST 与前缀 / 度量树 / 递归:visit 写在哪,就是哪种序 待审核 1 / 10
递归 · 遍历的定义本身

递归:visit 写在哪,就是哪种序

遍历的定义本身就是递归的:遍历一棵树 = 访问根、遍历左子树、遍历右子树。把这三件事写成 dfs(node) 里的三句话,前 / 中 / 后序的唯一区别就是 visit(node) 这一句相对 dfs(node.left)dfs(node.right) 摆在哪个位置:之前是前序、之间是中序、之后是后序。其余代码一字不差

本页约定: 演示树是二叉搜索树 (BST)(左 < 根 < 右),故中序输出恰为升序,便于对照。当前正在执行的节点 node橙色描边;已访问节点填实心青色。下方调用栈那条横条 = 从根到当前节点的祖先链——每次进入 dfs 入栈、返回时出栈,它就是递归占用的 O(h) 额外空间(h 为树高)。

三序只差一行的位置。 切换上面的开关,盯住代码里 visit(node) 那一句:它从 dfs(left)(前序)挪到两个 dfs(中序)、再挪到之(后序),输出序列随之改变,而调用栈的压入 / 弹出节奏完全一样——这说明「访问什么顺序」与「怎么走完树」是两件独立的事。

1 · 递归的代价:调用栈与爆栈风险

递归看似没有「数据结构」,但它借用了语言运行时的调用栈:每层 dfs 的局部变量、返回地址都压在调用栈上,栈的最大深度 = 树高 h。平衡树 h ≈ log n,但退化成链(如按升序插入 BST)时 h = n——试试上面的「右链」预设,看调用栈一路压到底。深度很大时(几万层)可能爆栈 (stack overflow),这正是显式栈迭代把调用栈搬到堆上、以及 Morris 索性省掉栈的动机。