0

我一直在研究算法和数据结构,并且我为二叉树编写了一个后序遍历,没有使用递归并且只使用一个堆栈。

这是代码:

def postorder_iterative(self):
    current = self
    s = []
    current1 = None
    done = 0
    def peek(s):
        return s[-1]

    while(not done):
        if current and (current != current1):
            s.append(current)
            current = current.leftChild
        elif(len(s) > 0):
            if peek(s).rightChild and peek(s).rightChild != current:
                current = peek(s).rightChild
            else:
                current = current1 = s.pop()
                print(current.key)
        else:
            done = 1

这段代码确实有效,但我花了很长时间才想出它。

有人可以解释一下思考这个问题的直观方式是什么吗?

我希望能够使用逻辑来重现它,而不是像我在它上面花费的时间一样多。

4

1 回答 1

3

后序遍历要求您仅在遍历左右子树后才打印当前节点值。您正在使用堆栈仅遍历左侧树,并使用current1变量(打印的最后一个节点)知道您现在正在退出右侧树,因此您可以打印当前节点。

我将重命名currentnode, (对于current1最后打印的),删除函数以直接引用为(堆栈顶部),并简化您的方法:lastpeek()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
于 2019-02-11T17:57:47.713 回答