从有序和后序遍历构造二叉树

时间:2019-06-24 05:49:10

标签: algorithm recursion tree depth-first-search

我正在尝试从后置顺序和有序遍历构造二叉树。我相信递归部分是正确的,但是我不确定基本情况。任何指针将不胜感激。

我尝试了不同的基本案例组合,但似乎无法正常工作。

class BinaryTreeNode:
    def __init__(self, data=None, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right


def binary_tree_from_postorder_inorder(postorder, inorder):
    node_to_inorder_idx = {data: i for i, data in enumerate(inorder)}


    def helper(
        postorder_start, postorder_end, inorder_start, inorder_end
    ):
        if postorder_end >= postorder_start or inorder_end <= inorder_start:
            return None


        root_inorder_idx = node_to_inorder_idx[postorder[postorder_start]]
        left_subtree_size = root_inorder_idx - inorder_start

        root = BinaryTreeNode(postorder[postorder_start])

        root.right = helper(
            postorder_start - 1,
            postorder_start - 1 - left_subtree_size,
            root_inorder_idx + 1,
            inorder_end,
        )
        root.left = helper(
            postorder_start - 1 - left_subtree_size,
            postorder_end,
            inorder_start,
            root_inorder_idx,
        )

        return root

     return helper(len(postorder) - 1, -1, 0, len(inorder))

def inorder(tree):
    stack = []
    results = []

    while stack or tree:
        if tree:
            stack.append(tree)
            tree = tree.left
        else:
            tree = stack.pop()
            results.append(tree.data)
            tree = tree.right
    return results


inorder = ["F", "B", "A", "E", "H", "C", "D", "I", "G"]
postorder = ["F", "A", "E", "B", "I", "G", "D", "C", "H"]

root_pos_in = binary_tree_from_postorder_inorder(postorder, inorder)

print(inorder(root_pos_in))

输入:

inorder = ["F", "B", "A", "E", "H", "C", "D", "I", "G"]
postorder = ["F", "A", "E", "B", "I", "G", "D", "C", "H"]

使用顺序遍历的实际输出: ["A", "B", "E", "H", "C"]

预期输出: ["F", "B", "A", "E", "H", "C", "D", "I", "G"]

2 个答案:

答案 0 :(得分:1)

自从我处理Python以来已经有一段时间了,但是对于看似简单的算法来说,这看起来像很多代码。

以下是该算法的应用示例:

我们从

开始
postorder  |  inorder
-----------|----------
           |               
FAEBIGDCH  | FBAEHCDIG
        ^  |
        |  |
         `-+-------------- last value of postorder: 'H': this is the root value
           |               
FAEBIGDCH  | FBAEHCDIG
           |     ^
           |     |
           |      `------- index of 'H' in inorder: 4
           |               
FAEB_....  | FBAE_....
  ^        |   ^
  |        |   |
  |        |    `--------- everything before index 4
  |        |
   `-------+-------------- everything before index 4
           |               
....IGDC_  | ...._CDIG
      ^    |        ^ 
      |    |        |
      |    |         `---- everything beginning with index 5 (4 + 1)
      |    |
       `---+-------------- everything between index 4 and the 'H' at the end
           |               
FAEB       | FBAE
  ^        |   ^
  |        |   |
   `-------+---+---------- recur on these if not empty: this is the left child
           |               
     IGDC  |      CDIG
       ^   |        ^
       |   |        |
        `--+--------+----- recur on these if not empty: this is the right child

这将很快将我们引向一棵像

的树
               H
               |
      +--------+--------+
      |                 |
      B                 C
      |                 |
+-----+-----+           +-----+
|           |                 |
F           E                 D
            |                 |
        +---+                 +---+
        |                         |
        A                         G
                                +-+
                                |
                                I

因此,尽管我不能真正批评您的Python,但我可以提供一个非常简单的JS版本:

const makeTree = (
    postord, inord, 
    len = postord.length, val = postord[len - 1], idx = inord.indexOf(val)
  ) =>
    len == 1
      ? {val}
    : {
        val,
        ...(idx > 0 ? {left: makeTree(postord.slice(0, idx), inord.slice(0, idx))} : {}),
        ...(idx < len - 1 ? {right: makeTree(postord.slice(idx, len - 1), inord.slice(idx + 1, len))} : {})
      }

const postOrder = ["F", "A", "E", "B", "I", "G", "D", "C", "H"]
const inOrder =   ["F", "B", "A", "E", "H", "C", "D", "I", "G"]

console .log (
  makeTree (postOrder, inOrder)
)

答案 1 :(得分:0)

摆弄一会儿之后,我得以解决此问题。请参阅下面的更新功能:

def binary_tree_from_postorder_inorder(postorder, inorder):
    if not inorder or not postorder or len(postorder) != len(inorder):
        return None

    node_to_inorder_idx = {data: i for i, data in enumerate(inorder)}

    def helper(postorder_start, postorder_end, inorder_start, inorder_end):
        if postorder_start > postorder_end or inorder_start > inorder_end:
            return None

        root_index = node_to_inorder_idx[postorder[postorder_end]]
        left_subtree_size = root_index - inorder_start

        return BinaryTreeNode(
            postorder[postorder_end],
            helper(
                postorder_start,
                postorder_start + left_subtree_size - 1,
                inorder_start,
                root_index - 1,
            ),
            helper(
                postorder_start + left_subtree_size,
                postorder_end - 1,
                root_index + 1,
                inorder_end,
            ),
        )

    return helper(0, len(postorder) - 1, 0, len(inorder) - 1)