📜  数据结构 |树遍历 |问题 5(1)

📅  最后修改于: 2023-12-03 15:40:00.588000             🧑  作者: Mango

数据结构 | 树遍历 | 问题 5

在这个问题中,我们需要实现二叉树的后序遍历。所谓后序遍历,就是先遍历左子树,然后遍历右子树,最后遍历根节点。

解法

递归是二叉树遍历的常见解法之一,后序遍历也不例外。递归的过程中,我们先访问左子树,然后访问右子树,最后访问根节点。

以下是递归实现后序遍历的代码:

def postorderTraversal(root):
    if not root:
        return []
    res = []
    res += postorderTraversal(root.left)
    res += postorderTraversal(root.right)
    res.append(root.val)
    return res

在这段代码中,我们首先判断了当前节点是否为空。如果为空,则直接返回一个空列表。否则,我们先递归遍历左子树,然后递归遍历右子树,最后将根节点的值加入到结果列表中,并返回结果列表。

递归实现后序遍历的时间复杂度为 $O(n)$,其中 $n$ 是节点数目。不过需要注意的是,递归的过程中可能会占用较多的栈空间,容易导致栈溢出问题。

非递归实现后序遍历的方法与前序和中序遍历类似,使用一个栈来模拟递归的过程。不过,后序遍历的非递归实现相对于前序和中序来说,比较麻烦一些。

以下是非递归实现后序遍历的代码:

def postorderTraversal(root):
    if not root:
        return []
    res = []
    stack = []
    last_visit = None  # 标记上一个访问的节点
    while stack or root:
        if root:
            stack.append(root)
            root = root.left
        else:
            peek = stack[-1]
            if peek.right and last_visit != peek.right:
                root = peek.right
            else:
                res.append(peek.val)
                last_visit = stack.pop()
    return res

在这段代码中,我们首先判断当前节点是否为空。如果为空,则直接返回一个空列表。否则,我们定义两个变量 stacklast_visitstack 是用来模拟递归的栈,last_visit 则是用来标记上一个访问的节点。在循环中,如果当前节点不为空,就将其入栈,并进入其左子树;否则,取出栈顶元素 peek,如果 peek 的右子树存在且没有被访问过,则进入其右子树;否则,将 peek 的值加入到结果列表中,并将 peek 从栈中弹出。

非递归实现后序遍历的时间复杂度同样为 $O(n)$,不过需要注意的是最坏情况下,栈的深度可能会达到 $n$,因此空间复杂度为 $O(n)$。

总结

该问题要求实现二叉树的后序遍历。递归是二叉树遍历的常见解法之一,后序遍历也不例外。非递归实现后序遍历的方法与前序和中序遍历类似,但是需要注意它的特殊性质(需要标记上一个访问的节点),以及可能出现的栈溢出问题。该算法的时间复杂度均为 $O(n)$,空间复杂度为 $O(n)$。