Вместо того, чтобы звонить self.left/right.
in
_order_list()
, вы звоните self.left/right.
pre
_order_list()
.
Чтобы выполнить то, что вы хотите сделать, функция генератора может быть лучше (менее потребляет память и более питонна), чем накапливать значения в списке:
class Tree(object):
...
def in_order(self):
if self.left is not None:
for value in self.left.in_order():
yield value
yield self.value # <-- yielding the value of the node, not the node itself
if self.right is not None:
for value in self.right.in_order():
yield value
...
tree = Tree(...)
in_order_values = list(tree.in_order())
Таким образом, вам не нужно создавать список, если вы хотите перебирать только значения:
for value in tree.in_order():
...
Алгоритм работает следующим образом: генератор сначала рекурсивно спускается вдоль левой ветви каждого узла, пока не достигнет одного без левого подузла. Затем он возвращает значение текущего узла. После этого он делает то же самое на правом подузле, но начинается с текущего узла, а не с корневого узла. Если мы предположим, что в дереве нет циклов и бесконечных ветвей, то определенно будут листовые узлы, то есть узлы без левого или правого подузла. Узлы IOW, для которых достигаются оба базовых случая (self.left/right is None
). Поэтому рекурсивные вызовы вернутся, надеюсь, до того, как у нас не хватит памяти или не достигнет предела стека.
Цикл по self.left/right.in_order()
необходим в связи с тем, что возвращаемый вызов in_order()
является генератором, отсюда и название функция генератора . Возвращенный генератор должен быть как-то исчерпан, например, через петлю. В теле цикла мы заново выводим значения на один уровень, где они снова возвращаются, пока не достигнут верхнего уровня. Там мы используем значения.
Если вы хотите получить сами узлы, а не только их поля значений, вы можете сделать это следующим образом:
class Tree(object):
...
def in_order(self):
if self.left is not None:
for node in self.left.in_order():
yield node
yield self # <-- yielding the node itself
if self.right is not None:
for node in self.right.in_order():
yield node
Вероятно, вы захотите сделать это, потому что вы не только можете получить доступ к значениям узлов:
for node in tree.in_order():
do_something_with(node.value)
но вы также можете делать с узлами все, что захотите:
for node in tree.in_order():
whatever(node.some_other_attribute)