使用Python中的inorder和preorder遍历重构树

时间:2014-04-24 00:10:52

标签: python algorithm tree tree-traversal

我需要创建一个从preorder和inorder遍历构建树的函数,但是我不知道应该在哪里放置MakeNode和递归调用来正确构造树。

假设inorder和preorder都是一个int列表,下面的算法是否正确使用遍历来重建树?

def build(preorder, inorder):
    root = preorder[0]
    left subtree = inorder[:root-1]
    right subtree = inorder[root+1:]

如果是这样 - 如何采用递归方式使用该算法来构建堆(ArrayHeap)? 我有一个用于构造节点的类,然后我可以简单地使用heap.add(node)来创建堆。

假设我的类构建一个节点名为“MakeNode”,并按如下方式构造(出于语法目的):

Class MakeNode():
    def __init__(self, character, left=None, right=None):

要创建根节点,我需要编辑这样的函数:

def build(preorder, inorder, heap):
    root = preorder[0]
    node = MakeNode(root) # Creating root node here
    heap.add(node) # Adding to heap
    left subtree = inorder[:root-1]
    right subtree = inorder[root+1:]

但是我应该如何使用递归来构建树的其余部分呢? 我可以通过这样做来合并左右预订单以进行订购:

def build(preorder, inorder, heap):
    root = preorder[0]
    node = MakeNode(root)
    heap.add(node)
    left subtree = inorder[:root-1]
    # order of left subtree = preorder[1:1+left subtree]
    right subtree = inorder[root+1:]
    # order of right subtree = preorder[root+1:]

我真的不知道如何合并递归调用来构建树,或者在执行此操作时如何为左或右参数添加确切的内容。

如果有人有任何建议我会很感激,如果我不清楚,我很抱歉。

3 个答案:

答案 0 :(得分:1)

您需要做的是将预先排序的列表的根添加到树中,然后将其从预订单列表中删除。按顺序拆分顺序列表,然后递归传递左右分支。继续在前一节点的左侧添加预订的第一个元素,除非left_subtree为空,然后您需要将其添加到右侧。

这样的事情(因为你要求伪代码而没有经过彻底的测试)

class tree():
    def __init__(self, inorder, preorder):
        self.root = preorder[0]
        lt = inorder[:index(self.root) - 1]
        rt = inorder[index(self.root) + 1:]
        self.build(self.root, lt, rt, preorder[1:]

    def build(self, last_node, left_subtree, right_subtree, preorder):
        if len(left_subtree) > 0:
            last_node.left = preorder[0]
            last_node = last_node.left
            lt = left_subtree[:index(preorder[0]) - 1]
            rt = left_subtree[index(preorder[0]) + 1:]
            self.build(last_node, lt, rt, preorder1:]
        elif len(right_subtree) > 0:
            last_node.right = preorder[0]
            last_node = last_node.right
            lt = right_subtree[:index(preorder[0]) - 1]
            rt = right_subtree[index(preorder[0]) + 1:]
            self.build(last_node, lt, rt, preorder1:]

答案 1 :(得分:1)

http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html开始,您有:

parent(i) = i/2
left(i) = 2i
right(i) = 2i+1

所以你可以定义一个类:

class ArrayHeapNode:
    def __init__(self, elements, index):
        self.elements = elements
        self.index = index

    def left(self):
        next = self.index * 2
        if next >= len(self.elements):
            return None
        return ArrayHeapNode(self.elements, next)

    def right(self):
        next = (self.index * 2) + 1
        if next >= len(self.elements):
            return None
        return ArrayHeapNode(self.elements, next)

    def value(self):
        return self.elements[self.index]

    def set_value(self, _value):
        self.elements[self.index] = _value

根据文章,这为您提供了一个类,该类可以作为二进制堆的数组表示形式的树。如果该分支中没有元素,则返回None

您现在可以创建树遍历算法(https://en.wikipedia.org/wiki/Tree_traversal):

def inorder_traversal(node, action):
    if not node: return
    inorder_traversal(node.left(), action)
    action(node.value())
    inorder_traversal(node.right(), action)

def preorder_traversal(node, action):
    if not node: return
    action(node.value())
    preorder_traversal(node.left(), action)
    preorder_traversal(node.right(), action)

这些也适用于传统的二叉树节点:

class BinaryTreeNode:
    def __init__(self, value, left, right):
        self._value = value
        self._left = left
        self._right = right

    def left(self):
        return self._left

    def right(self):
        return self._right

    def value(self):
        return self._value

    def set_value(self, _value):
        self._value = _value

现在,您可以通过执行以下操作使遍历算法更加灵活和类似python:

def inorder(node):
    if node:
        for item in inorder(node.left()):
            yield item
        yield node.value()
        for item in inorder(node.right()):
            yield item

这允许您编写如下内容:

for item in inorder(tree):
    print item

然后,您可以通过执行以下操作来计算节点中的元素:

n = sum(1 for e in inorder(root))

然后,这允许您创建一个空数组,该数组能够为堆中的元素保存n个元素:

elements = [0 for x in range(n)]

或合并:

elements = [0 for x in inorder(root)]
heap = ArrayHeapNode(elements, 0)

现在,您可以使用以下方法同时迭代两棵树:

for a, b in zip(inorder(root), inorder(heap)):
    b = a

然后,应该使用inorder遍历将二叉树中的所有元素(root)分配给数组堆中的正确元素(heap)。通过实现preorder函数也可以做到这一点。

注意:我没有测试过这段代码。

答案 2 :(得分:0)

def pre_order(node):
    print node #pre order ... print ourself first
    pre_order(node.left)
    pre_order(node.right)

def post_order(node):
    post_order(node.left)
    post_order(node.right)
    print node # post order print self last...

def in_order(node):
    in_order(node.left)
    print node  #in order ... between its children
    in_order(node.right)

如果你有其中任何一个,你应该能够重现树

假设我们有这样的树

    0
 1     2
3 4   5 6

我们的遍历将是

0,1,3,4,2,5,6 #pre order
3,1,4,0,5,2,6 #in order

所以我们知道

  1. 零是我们的根
  2. 3是我们最左边最深的节点
  3. 6是我们最深的节点
  4. 0 ... 3 6

    我们的遗留节点是

     1,4,2,5 # preorder
     1,4,5,2 # in-order
    

    由此我们知道

    1. 1是零
    2. 的孩子
    3. 1是最左边的下一个节点
    4. 2是下一级最右边的节点
    5. 所以我们现在有了

            0
         1      2
       3          6
      

      离开我们

      4,5 # pre order
      4,5 # in order
      

      由此我们知道4是1的孩子,因此5必须是2的孩子......

      现在编写一个完成所有操作的函数

      这篇文章可能有所帮助

      http://leetcode.com/2011/04/construct-binary-tree-from-inorder-and-preorder-postorder-traversal.html