算法记录 | Day13二叉树

61 阅读3分钟

算法记录 | Day13二叉树

二叉树的节点定义

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
-------------------------------------------------------------
 LeetCode 144-二叉树的前序遍历
 LeetCode 145-二叉树的后序遍历
 LeetCode 94-二叉树的中序遍历

二叉树的前序、中序、后序遍历

题目链接:

leetcode.cn/problems/bi…

leetcode.cn/problems/bi…

leetcode.cn/problems/bi…

递归遍历

解题思路
  • 递归算法的三要素
    • 确定递归函数的参数和返回值
    • 确定终止条件
    • 确定单层递归的逻辑
难点
  • 递归思想

  • 递归法

# 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 preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        # 保存结果
        result = []
        
        def traversal(root: TreeNode):
            if root == None:
                return
            result.append(root.val) # 前序
            traversal(root.left)    # 左
            traversal(root.right)   # 右

        traversal(root)
        return result

# 后序遍历
class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        result = []
        def reversal(root):
            if not root:
                return
            reversal(root.left)
            reversal(root.right)
            result.append(root.val)
        reversal(root)
        return result

# 中序遍历
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        result = []
        def reversal(root):
            if not root:
                return
            reversal(root.left)
            result.append(root.val)
            reversal(root.right)
        reversal(root)
        return result

写法二:

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        # 保存结果
        if not root:
            return []
        return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
总结
  • 递归的整个过程需要再写一个函数,我之前记忆的是写法二这种。
  • 递归还是靠感觉。这个过程仿佛对我并不起什么作用。

迭代遍历

在[ 栈与队列:匹配问题都是栈的强项 ]中提到了,递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。

解题思路
  • 栈与队列的原理实现
  • 整个过程其实和递归遍历的整个过程类似
# 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 preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        stack = [root]
        # print(stack)
        result = []
        while stack:
            node = stack.pop()
            result.append(node.val)
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)
        return result
# 中序遍历(左中右)
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        stack = [] # 不能提前将root结点加入stack中
        # print(stack)
        result = []
        cur = root
        while cur or stack:
            if cur:
                stack.append(cur)
                cur = cur.left
            else:
                cur = stack.pop()
                result.append(cur.val)
                cur = cur.right
        return result
# 后序遍历(左右中)----刚好是前序反过来
class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            # 中结点先处理
            result.append(node.val)
            # 左孩子先入栈
            if node.left:
                stack.append(node.left)
            # 右孩子后入栈
            if node.right:
                stack.append(node.right)
        # 将最终的数组翻转
        return result[::-1]
难点
  • 中序遍历与前序遍历和后序遍历是最不一样的

统一遍历

针对三种遍历方式,使用迭代法是可以写出统一风格的代码

解题思路
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        result = []
        st = []
        if root:
            st.append(root)
        while st:
            node = st.pop()
            if node != None:
                if node.right: #添加右节点(空节点不入栈)
                    st.append(node.right)
                
                st.append(node) #添加中节点
                st.append(None) #中节点访问过,但是还没有处理,加入空节点做为标记。
                
                if node.left: #添加左节点(空节点不入栈)
                    st.append(node.left)
            else: #只有遇到空节点的时候,才将下一个节点放进结果集
                node = st.pop() #重新取出栈中元素
                result.append(node.val) #加入到结果集
        return result
难点
  • 太多了,有点混乱了,不太好理解