【问题标题】:Iterative postorder traversal of a binary tree with a single stack, how to approach the problem?具有单个堆栈的二叉树的迭代后序遍历,如何解决这个问题?
【发布时间】:2019-02-11 17:14:44
【问题描述】:

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

代码如下:

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

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

谁能解释一下这个问题的直观思考方式是什么?

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

【问题讨论】:

    标签: python iteration binary-search-tree tree-traversal postorder


    【解决方案1】:

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

    我会将current 重命名为node,将current1 重命名为last(对于上次打印),删除peek() 函数以将stack[-1] 直接引用为@ 987654328@(堆栈顶部),并简化您的方法:

    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))
    

    节点通过三种状态,只需增加状态标志。它们从 new 节点开始,然后前进到 left,然后是 right,当堆栈顶部处于最后一个状态时,我们将其移除从堆栈中打印节点值。

    当仍处于 newleft 状态时,我们将左侧或右侧节点(如果存在)作为新节点添加到堆栈中。

    另一种方法是在当前节点之前将右侧树推入堆栈。稍后,当您从堆栈中取出当前节点时,您可以检测到仍然需要处理右侧的情况,因为堆栈顶部将具有右侧节点。在这种情况下,您将堆栈顶部与当前节点交换并从那里继续;您稍后将返回同一个位置,并且堆栈顶部将不再有该右侧节点,因此您可以打印:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多