后序遍历(Post-order Traversal)

一句话说明

后序遍历是“左、右、根”,也就是先拿到左右子树结果,最后再处理当前节点。

顺序先记死

左 -> 右 -> 根

示例:

      1
     / \
    2   3
   / \
  4   5

后序结果:

[4, 5, 2, 3, 1]

为什么它特别适合“自底向上”

因为当前节点要最后处理。
这意味着:

  • 左子树答案先出来
  • 右子树答案也先出来
  • 当前节点最后把它们合并

所以后序遍历天然适合:

  • 求树高
  • 判断平衡树
  • 最大路径和
  • 树形 DP

Go 代码:递归后序

func PostorderTraversal(root *TreeNode) []int {
    result := []int{}
 
    var dfs func(node *TreeNode)
    dfs = func(node *TreeNode) {
        if node == nil {
            return
        }
        dfs(node.Left)
        dfs(node.Right)
        result = append(result, node.Val)
    }
 
    dfs(root)
    return result
}

Go 代码:双栈迭代

func PostorderTraversalIterative(root *TreeNode) []int {
    if root == nil {
        return nil
    }
 
    stack1 := []*TreeNode{root}
    stack2 := []*TreeNode{}
 
    for len(stack1) > 0 {
        node := stack1[len(stack1)-1]
        stack1 = stack1[:len(stack1)-1]
        stack2 = append(stack2, node)
 
        if node.Left != nil {
            stack1 = append(stack1, node.Left)
        }
        if node.Right != nil {
            stack1 = append(stack1, node.Right)
        }
    }
 
    result := make([]int, 0, len(stack2))
    for i := len(stack2) - 1; i >= 0; i-- {
        result = append(result, stack2[i].Val)
    }
    return result
}

双栈法为什么成立

第一层栈弹出来的顺序近似是:

根 -> 左 -> 右

第二个栈再倒过来,就得到:

左 -> 右 -> 根

这正好就是后序。

常见题型

  • 树的高度
  • 平衡二叉树
  • 最大路径和
  • 删除整棵树
  • 各类树形 DP

易错点

后序遍历最容易错的地方

  • 当前节点的处理语句必须放在最后。
  • 很多树题本质不是“要求你输出后序”,而是要求你按后序位置做状态合并。

复杂度

实现方式时间复杂度空间复杂度
递归O(n)O(h)
双栈迭代O(n)O(n)

相关主题


返回:树算法 | 算法学习导航