代码随想录训练营第十四天| 二叉树的前中后序遍历(递归法和统一迭代法)

116 阅读4分钟

一、递归遍历尔察使

144. 二叉树的前序遍历 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

要返回的是一个list,但是这个函数似乎又没有传参传list,与其创建新的DFS函数,不如直接做个成员变量记录结果。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.node_list = list()

    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if root is None:
            return self.node_list
        else:
            self.node_list.append(root.val)
            if root.left:
                self.preorderTraversal(root=root.left)
            if root.right:
                self.preorderTraversal(root=root.right)
            return self.node_list

145. 二叉树的后序遍历 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.node_list = list()

    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if root is None:
            return self.node_list
        else:
            if root.left:
                self.postorderTraversal(root=root.left)
            if root.right:
                self.postorderTraversal(root=root.right)
            self.node_list.append(root.val)
            return self.node_list

94. 二叉树的中序遍历 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.node_list = list()

    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if root is None:
            return self.node_list
        else:
            if root.left:
                self.inorderTraversal(root=root.left)
            self.node_list.append(root.val)
            if root.right:
                self.inorderTraversal(root=root.right)
            return self.node_list

二、迭代遍历

144. 二叉树的前序遍历 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

首先一定要注意不是递归,我们用栈就是要代替递归的。 既然要代替递归,我们一个过程就完事,不要搞太多函数。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.node_list = list()
        self.stack = list()

    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if root is None:
            return self.node_list
        else:
            self.stack.append(root)
            while self.stack:
                node = self.stack.pop()
                if node.right:
                    self.stack.append(node.right)
                if node.left:
                    self.stack.append(node.left)
                self.node_list.append(node.val)
            return self.node_list

145. 二叉树的后序遍历 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

关键是什么时候停止节点入栈,直观地理解上当然是所有叶子节点都已入栈就终止。 但是我们其实可以做到用一个循环就连最后的遍历结果也输出,那就是:

  1. 每pop一个node,看这个node是否有一个左孩子或者右孩子。
  2. 如果有,那就不是叶子,我们把它们的孩子加进来,但是在加进来之前,我们还是把node放回栈,再加孩子。但是如果这样的话,每次pop到这个node,我们还是会把左右孩子压进栈来。这样就陷入了无限循环,不停的加入同样的node左右孩子。所以我们应该在压入左右孩子前,先把node的左右孩子砍掉,变成独立节点,这样他就被认为是叶子,就不会再压入他的左右孩子了。
  3. 如果遇到没有左右孩子的node,就应该果断把他pop出来,把值放进结果列表里就可以了。
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.node_list = list()
        self.stack = list()

    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if root is None:
            return self.node_list
        else:
            self.stack.append(root)
            while self.stack:
                node = self.stack.pop()
                if (node.left is None) and (node.right is None):
                    self.node_list.append(node.val)
                else:
                    self.stack.append(TreeNode(node.val, None, None))
                    if node.right:
                        self.stack.append(node.right)
                    if node.left:
                        self.stack.append(node.left)
            return self.node_list

3. 看完代码随想录之后的想法

文档使用的是前序遍历(但是不是中左右,而是中右左)得到的结果列表就需要反转一下就行。

4. 学习时长

30分钟

94. 二叉树的中序遍历 - 力扣(LeetCode)

1. 文章链接

代码随想录 (programmercarl.com)

2. 看到题目的第一想法

输出的node,先压入他的node.right, 再压入被砍掉左右孩子的node,最后压入node.left. 如果遇见无子的节点(叶子节点或被砍去左右孩子的节点)就出栈。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.node_list = list()
        self.stack = list()

    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if root is None:
            return self.node_list
        else:
            self.stack.append(root)
            while self.stack:
                node = self.stack.pop()
                if (node.left is None) and (node.right is None):
                    self.node_list.append(node.val)
                else:
                    if node.right:
                        self.stack.append(node.right)
                    self.stack.append(TreeNode(val=node.val))
                    if node.left:
                        self.stack.append(node.left)
            return self.node_list
            

我觉得我这个实现好,和后序遍历很一致。

三、统一迭代法

代码随想录 (programmercarl.com)文档中使用的所谓统一的方法,其基本思想与我自己上面写的很一致,唯一的区别就是他用一个node后面是否有None来表达。但是我们直接将node砍成无子节点,达到同样的效果。