后序遍历要求您仅在遍历左右子树后才打印当前节点值。您正在使用堆栈仅遍历左侧树,并使用current1
变量(打印的最后一个节点)知道您现在正在退出右侧树,因此您可以打印当前节点。
我将重命名current
为node
, (对于current1
最后打印的),删除函数以直接引用为(堆栈顶部),并简化您的方法:last
peek()
stack[-1]
tos
def postorder_iterative(self):
node, last = self, None
stack = []
while True:
if node and node is not last:
# build up the stack from the left tree
stack.append(node)
node = node.leftChild
elif stack:
# no more left-hand tree to process, is there a right-hand tree?
tos = stack[-1]
if tos.rightChild and tos.rightChild is not node:
node = tos.rightChild
else:
# both left and right have been printed
node = last = stack.pop()
print(last.key)
else:
break
然而,仍然很难理解正在发生的事情,因为last
左右子树之间的连接和处理点之间的联系并不是那么清楚。
我会使用带有状态标志的单个堆栈来跟踪您在进程中的位置:
def postorder_iterative(self):
new, left_done, right_done = range(3) # status of node
stack = [[self, new]] # node, status
while stack:
node, status = stack[-1]
if status == right_done:
stack.pop()
print(node.key)
else:
stack[-1][1] += 1 # from new -> left_done and left_done -> right_done
# new -> add left child, left_done -> add right child
next_node = [node.leftChild, node.rightChild][status]
if next_node is not None:
stack.append((next_node, new))
节点通过三种状态,只需增加状态标志。它们从新节点开始,然后前进到left,然后是 right,当堆栈顶部处于最后一个状态时,我们将其从堆栈中删除并打印节点值。
当仍处于新或左状态时,我们将左或右节点(如果存在)作为新节点添加到堆栈中。
另一种方法是在当前节点之前将右侧的树推入堆栈。稍后,当您从堆栈中取出当前节点时,您可以检测到仍然需要处理右侧的情况,因为堆栈顶部将具有右侧节点。在这种情况下,您将堆栈顶部与当前节点交换并从那里继续;您稍后将返回同一位置,并且将不再在堆栈顶部具有该右侧节点,因此您可以打印:
def postorder_iterative(self):
stack = []
node = self
while node or stack:
while node:
# traverse to the left, but add the right to the stack first
if node.rightChild is not None:
stack.append(node.rightChild)
stack.append(node)
node = node.leftChild
# left-hand tree traversed, time to process right or print
node = stack.pop()
if stack and node.rightChild is stack[-1]:
# right-hand tree present and not yet done, swap tos and node
node, stack[-1] = stack[-1], node
else:
print(node.key)
node = None