二叉树的非递归后序遍历算法实例详解


当然,我可以提供一个二叉树的非递归后序遍历(Left-Right-Root, LRR)的算法实例详解。非递归后序遍历通常需要使用栈(Stack)来实现,因为后序遍历的顺序是左-右-根,这与栈的先进后出(FILO)特性相契合。

### 算法步骤

1. **初始化栈**:首先,我们需要一个栈来辅助遍历过程。

2. **根节点入栈**:将根节点压入栈中。

3. **循环处理**:当栈不为空时,执行以下步骤:

- 弹出栈顶元素(记为`node`)。

- 如果`node`的右子节点存在且未被访问过(可以通过标记或栈来判断),则将右子节点压入栈中。

- 如果`node`的左子节点存在且未被访问过,则将左子节点压入栈中。

- 如果`node`的左右子节点都已被访问过(或不存在),则访问`node`(即输出或处理节点)。

但是,由于直接按照上述步骤操作无法直接判断一个节点是否已被访问过,我们通常需要使用额外的数据结构(如另一个栈、标记数组或哈希表)来记录哪些节点已被访问。然而,为了简化实现,这里我们使用一种技巧:在节点第一次入栈时,压入的是节点本身;在节点需要被访问时(即左右子节点都已被处理),我们再次将其压入栈,但这次压入的是一个特殊的标记(比如`null`或者一个特定值),以表示该节点需要被访问。

### 示例代码(Python)


class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def postorderTraversal(root):
    if not root:
        return []

    stack, output = [root], []

    while stack:
        node = stack.pop()

        # 如果当前节点是None,表示其左右子树都已被访问,访问该节点
        if node is None:
            output.append(stack.pop().val)
            continue

        # 否则,将右子树、左子树、节点本身(作为需要访问的标记)依次入栈
        if node.right:
            stack.append(node.right)
        if node.left:
            stack.append(node.left)
        stack.append(node)
        stack.append(None)  # 标记节点需要被访问

    return output[::-1]  # 因为是逆序访问的,所以最后需要反转结果

# 示例使用
# 构建一棵简单的树
#       1
#      / \
#     2   3
#    / \
#   4   5
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)

print(postorderTraversal(root))  # 输出: [4, 5, 2, 3, 1]

注意:上面的代码实现中,我使用了`None`作为标记来指示节点需要被访问。当栈中弹出`None`时,我们知道接下来应该访问栈顶的节点。此外,由于我们的访问顺序是逆序的,最后需要将结果列表反转。这种方法虽然简单,但在实际应用中可能需要额外的空间来存储标记,并且逻辑上可能稍显复杂。对于更复杂或高效的实现,可以考虑使用两个栈或其他数据结构来优化。