Вот мой рекурсивный итеративный перевод с использованием frame_stack:
def traverse_iter(node):
# Iterative bst traversal. A (node, state) tuple is pushed onto frame_stack where a recursive call would occur.
# state defines where to pick up the processing on return (on pop).
# state: 0: Did not just return into this frame.
# 1: Just returned from left child.
# 2: Just returned from right child.
# Only states 1 and 2 get pushed onto the frame_stack.
# Generally, state would include any variables that are needed on return that get changed on the frame change
# in addition to the program counter (pc).
# Here, each node has all the data (val) needed, and state 1 or 2 acts as a pc to determine where to pick up
# on return.
frame_stack = []
state = 0 # Didn't just return from a child(function call).
while True:
if node is None:
if frame_stack: # Returning up recursion tree:
node, state = frame_stack.pop()
else: # or completed traversal.
break
if state == 0:
# Execute pre-order work here.
#print(node.val, end=' ')
if node.lft: # Emmulate recursive call into left child.
frame_stack.append((node, 1))
node = node.lft
continue
if state == 0 or state == 1:
# Execute in-order work here
print(node.val, end=' ')
if node.rt:
frame_stack.append((node, 2))
node = node.rt
state = 0 # State to descend into child.
continue
# Returning from a right child or there was none:
# Execute post-order work here.
# print(node.val, end=' ')
node = None # finished with this node (and all below it).
Как только я «понял», я обнаружил, что довольно просто разработать и понять вышеизложенное, и кажется, что шаблон, который я использовал, обычно расширяемый для любого рекурсивного итеративного перевода, поскольку он основан на том, что делает компьютер. Я в основном перевожу рекурсивный вызов функции в обновление переменных, которые меняются в новую функцию (узел на дочерний узел здесь), и pu sh их исходные значения в стек фрейма (узел здесь) вместе с p c (укажите здесь); минимальная логика поддержки c была добавлена по мере необходимости.
Мне интересно, может ли кто-нибудь привести пример, когда полезная нагрузка кадра требует больше, чем (узел, состояние), чтобы получить из функции return, где мы остановились, или упростить мой обход BST (сохраняя при этом предварительно, in- и post-order general).