Начните с рекурсивного алгоритма (псевдокод):
traverse(node):
if node != None do:
traverse(node.left)
print node.value
traverse(node.right)
endif
Это явный случай рекурсии хвоста, так что вы можете легко превратить его в цикл while.
traverse(node):
while node != None do:
traverse(node.left)
print node.value
node = node.right
endwhile
Вы остались с рекурсивным вызовом. Что делает рекурсивный вызов, так это помещает новый контекст в стек, запускает код с самого начала, затем извлекает контекст и продолжает делать то, что делал. Таким образом, вы создаете стек для хранения и цикл, который определяет на каждой итерации, в какой ситуации мы находимся в «первом запуске» (ненулевой узел) или в ситуации «возврата» (нулевой узел, непустой стек ) и запускает соответствующий код:
traverse(node):
stack = []
while !empty(stack) || node != None do:
if node != None do: // this is a normal call, recurse
push(stack,node)
node = node.left
else // we are now returning: pop and print the current node
node = pop(stack)
print node.value
node = node.right
endif
endwhile
Трудно понять, что является частью «возврата»: вы должны определить в цикле, находится ли выполняемый код в ситуации «входа в функцию» или в ситуации «возврата из вызова» и у вас будет цепочка if/else
с таким количеством случаев, сколько у вас нет нетерминальных рекурсий в вашем коде.
В этой конкретной ситуации мы используем узел для хранения информации о ситуации. Другой способ - сохранить это в самом стеке (как это делает компьютер для рекурсии). При таком способе код становится менее оптимальным, но его легче выполнять
traverse(node):
// entry:
if node == NULL do return
traverse(node.left)
// after-left-traversal:
print node.value
traverse(node.right)
traverse(node):
stack = [node,'entry']
while !empty(stack) do:
[node,state] = pop(stack)
switch state:
case 'entry':
if node == None do: break; // return
push(stack,[node,'after-left-traversal']) // store return address
push(stack,[node.left,'entry']) // recursive call
break;
case 'after-left-traversal':
print node.value;
// tail call : no return address
push(stack,[node.right,'entry']) // recursive call
end
endwhile