结合递归和收益进行树遍历

时间:2019-01-25 02:38:13

标签: python recursion generator yield

我正在尝试将递归和yield结合起来以有序遍历一棵树

这就是我目前所拥有的。但是,当我尝试遍历树时,似乎只遍历根节点

class Tree:
    ...
    def post_order(self, node: TreeNode):
        """Yield next node in post order from node"""
        for child in node.get_children():
            self.post_order(child)
        yield node


if __name__ == '__main__':
    root = TreeNode('root')
    depth1a = TreeNode('1a')
    depth1b = TreeNode('1b')
    root.add_children(depth1a, depth1b)
    tree = Tree(root)
    for node in tree.post_order(root):
        print(node.get_element())

运行代码时,它只会打印出来

root

这是第一个节点的元素,而不是我想要的

1a
1b
root

有人知道我做错了吗?

谢谢大家

2 个答案:

答案 0 :(得分:1)

感谢张实唯,事实证明我必须使用yield from。调用生成器函数不会从中产生:

class Tree:
    ...
    def post_order(self, node: TreeNode):
        """Yield next node in post order from node"""
        for child in node.get_children():
            yield from self.post_order(child)
        yield node

答案 1 :(得分:0)

迈克·潘(Mike Pham)的回答很好,但是我想分享一种回溯方法,该方法可以帮助我们了解如何使用直接递归而不是for循环来手动构建所需的序列。这不是一个更好的程序。这是检查您对发电机的掌握程度的一种练习-

from functools import reduce

def empty ():
  yield from ()

def postorder (node, backtrack = empty(), visit = False):
  if visit:
    yield node.data
    yield from backtrack
  elif node.children:
    yield from reduce \
      ( lambda it, child: postorder (child, it)
      , node.children[::-1]
      , postorder (node, backtrack, True)
      )
  else:
    yield from postorder (node, backtrack, True)

测试一下-

class node:
  def __init__ (self, data, *children):
    self.data = data
    self.children = children

tree = \
  node("a",
    node("b",
      node("e"),
      node("f",
        node("k"))),
    node("c"),
    node("d",
      node("g"),
      node("h"),
      node("i"),
      node("j")))

print(list(postorder(tree)))
# [ 'e', 'k', 'f', 'b', 'c', 'g', 'h', 'i', 'j', 'd', 'a' ]

这可能有助于您了解yield实际为您所做的事情。这是没有它的相同程序。 粗体-

的细微差别
def empty ():
  return []

def postorder (node, backtrack = empty, visit = False):
  def gen ():
    if visit:
      return [ node.data ] + backtrack()
    elif node.children:
      return reduce \
        ( lambda it, child: postorder (child, it)
        , node.children[::-1]
        , postorder (node, backtrack, True)
        ) ()
    else:
      return postorder (node, backtrack, True) ()
  return gen

def run (gen):
  return gen ()

print(run(postorder(tree)))
# [ 'e', 'k', 'f', 'b', 'c', 'g', 'h', 'i', 'j', 'd', 'a' ]