Ответ Майка Фэма великолепен, но я хотел поделиться подходом обратного отслеживания, который поможет нам понять, как мы можем вручную построить желаемую последовательность, используя прямую рекурсию вместо циклов 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):
<b>def gen ():</b>
if visit:
return <b>[</b> node.data <b>] + backtrack()</b>
elif node.children:
return reduce \
( lambda it, child: postorder (child, it)
, node.children[::-1]
, postorder (node, backtrack, True)
) <b>()</b>
else:
return postorder (node, backtrack, True) <b>()</b>
<b>return gen</b>
<b>def run (gen):
return gen ()</b>
print(<b>run</b>(postorder(tree)))
# [ 'e', 'k', 'f', 'b', 'c', 'g', 'h', 'i', 'j', 'd', 'a' ]