1. 简介

在本篇文章中,我们将探讨如何通过深度优先遍历序列重建二叉树。我们会以一个具体的二叉树为例,展示重建过程,并分析哪些遍历组合可以唯一重建出一棵二叉树。

2. 可用于重建二叉树的遍历组合

我们知道,二叉树可以通过不同的深度优先遍历方式来表示。要唯一重建一棵二叉树,通常需要结合两种遍历方式,因为单一的遍历结果不足以确定树的结构。

以下三种组合可以用于重建:

中序 + 先序
中序 + 后序
先序 + 后序(仅限满二叉树)

⚠️ 注意:除非是满二叉树,否则无法仅凭先序和后序重建出唯一的二叉树。因为这两种遍历方式无法区分某个节点是左孩子还是右孩子。

3. 实例演示

我们以下图这棵二叉树为例进行讲解:

full tree

该树的三种遍历结果如下:

traversals 1

4. 从先序与中序重建二叉树

4.1 重建逻辑

  • 先序遍历的第一个节点是根节点。
  • 在中序遍历中找到该根节点,其左边是左子树,右边是右子树。
  • 递归处理左子树和右子树。

示例步骤

  1. 先序第一个元素 6 是根节点。
  2. 在中序中找到 6,左边是 [2,3,4],右边是 [7,12,15,19]
  3. 接下来在先序中取下一个元素 3,它属于左子树。
  4. 在中序中找到 3,左边是 2,右边是 4
  5. 继续递归,直到整棵树构建完成。

4.2 算法实现(伪代码)

algorithm BuildTree(preorder, inorder):
    // INPUT
    //    preorder = array of nodes in preorder traversal
    //    inorder = array of nodes in inorder traversal
    //    preorderIndex = global variable initialized to 0
    // OUTPUT
    //    Reconstructs the binary tree from preorder and inorder traversal and returns the root node

    node <- preorder[preorderIndex]
    preorderIndex <- preorderIndex + 1

    inorderIndex <- the index of node in inorder

    inorderLeft <- inorder[0 : inorderIndex]
    inorderRight <- inorder[inorderIndex + 1 : length(inorder)]

    if length(inorderLeft) = 0 and length(inorderRight) = 0:
        return node

    node.left <- buildTree(preorder, inorderLeft)
    node.right <- buildTree(preorder, inorderRight)

    return node

5. 从后序与中序重建二叉树

5.1 重建逻辑

  • 后序遍历的最后一个节点是根节点。
  • 在中序中找到该节点,左边是左子树,右边是右子树。
  • 递归处理右子树,再处理左子树(因为后序遍历顺序是左→右→根)。

示例步骤

  1. 后序最后一个元素 6 是根节点。
  2. 在中序中找到 6,左边是左子树 [2,3,4],右边是右子树 [7,12,15,19]
  3. 后序倒数第二个元素是 19,属于右子树。
  4. 递归重建右子树和左子树。

5.2 算法实现(伪代码)

algorithm BuildTreePostIn(postorder, inorder):
    // INPUT
    //    postorder = array of nodes in postorder traversal
    //    inorder = array of nodes in inorder traversal
    //    postorderIndex = global variable initialized to the index of the last node: length(postorder) - 1
    // OUTPUT
    //    reconstructs the binary tree from postorder and inorder traversal and returns the root node

    node <- postorder[postorderIndex]
    postorderIndex <- postorderIndex - 1

    inorderIndex <- the index of node in inorder

    inorderLeft <- inorder[0 : inorderIndex]
    inorderRight <- inorder[inorderIndex + 1 : length(inorder)]

    if length(inorderRight) = 0 and length(inorderLeft) = 0:
        return node

    node.right <- buildTreePostIn(postorder, inorderRight)
    node.left <- buildTreePostIn(postorder, inorderLeft)

    return node

6. 从先序与后序重建二叉树

6.1 使用前提

⚠️ 只能用于满二叉树。否则无法区分左右孩子。

示例说明

我们以下图为例:

non full binary tree

这两棵树的先序和后序是相同的,因此无法区分结构。

6.2 重建逻辑(满二叉树)

  • 先序第一个元素是根节点。
  • 先序下一个元素是左孩子。
  • 在后序中找到该左孩子,确定其子树范围。
  • 递归构建左右子树。

6.3 算法实现(伪代码)

algorithm BuildTreePrePost(preorder, postorder):
    // INPUT
    //    preorder = array of nodes in preorder traversal
    //    postorder = array of nodes in postorder traversal
    //    preorderIndex = global variable initialized to 0
    // OUTPUT
    //    reconstructs the full binary tree from preorder and postorder traversal and returns the root node

    if preorderIndex >= length(preorder):
        return null

    node <- preorder[preorderIndex]
    if preorderIndex >= length(preorder) or node == postorder[length(postorder) - 1]:
        preorderIndex <- preorderIndex + 1
        return node

    leftChild <- preorder[preorderIndex + 1]
    postorderLeftIndex <- indexOf(postorder, leftChild)

    postorderLeft <- postorder[0 : postorderLeftIndex + 1]
    postorderRight <- postorder[postorderLeftIndex + 1 : length(postorder) - 1]

    node.left <- buildTreePrePost(preorder, postorderLeft)
    node.right <- buildTreePrePost(preorder, postorderRight)

    return node

7. 总结

本文介绍了三种通过深度优先遍历重建二叉树的方法:

组合方式 是否可唯一重建 条件说明
中序 + 先序 ✅ 是 通用方法
中序 + 后序 ✅ 是 通用方法
先序 + 后序 ✅ 是 仅限于满二叉树(每个节点有0或2个子节点)

📌 踩坑提醒:不要尝试用先序+后序去重建非满二叉树,否则会遇到歧义结构,无法唯一还原。

通过这些方法,我们可以根据已知的遍历顺序,递归重建原始二叉树结构。这在算法题、编译器设计、数据结构恢复等场景中有广泛应用。


原始标题:Reconstructing a Tree From Its Depth-First Traversals

» 下一篇: 分支限界算法详解