代码随想录二叉树小结1;(递归与迭代法小结)

发布于:2025-04-13 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、递归遍历

1.递归算法三要素:

  1. 确定递归函数的参数和返回值: 在递归函数里加上递归的过程中需要处理的参数, 然后明确每次递归的返回值是什么,最后确定递归函数的返回类型。

  2. 确定终止条件: 递归算法运行的时候,经常会遇到栈溢出的错误,一般就是没写终止条件或者终止条件有误。

  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息,重复调用自己来实现递归的过程。

2.以前序遍历为例(遍历顺序:中左右)

1.确定递归函数的参数和返回值:参数根节点:root,返回int类型列表

def preorderTraversal(self, root: TreeNode) -> List[int]:

2.确定终止条件:当前遍历节点为空

if node is None:
                return

3.确定单层递归的逻辑:前序遍历是中左右的顺序,所以在单层递归的逻辑,是要先取中节点的数值

            res.append(node.val)
            dfs(node.left)
            dfs(node.right)

完整前序遍历:

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: TreeNode) -> List[int]:
        res = []
        
        def dfs(node):
            if node is None:
                return
            
            res.append(node.val)    #中
            dfs(node.left)          #左
            dfs(node.right)         #右

        dfs(root)
        return res

中序和后续只需将调整“中左右”的逻辑顺序为“左中右”和“左右中”

            dfs(node.left)
            res.append(node.val)
            dfs(node.right)
            dfs(node.left)
            dfs(node.right)
            res.append(node.val)

二、二叉树的迭代遍历

1.前序遍历迭代

每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以递归可以返回上一层位置。

由于栈的“先入后出”的性质,对于前序遍历,每次先处理中间节点,首先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。为什么要先加入 右孩子,再加入左孩子呢? 因为这样出栈的时候才是中左右的顺序。

        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            # 中节点先处理
            result.append(node.val)
            # 右孩子先入栈
            if node.right:
                stack.append(node.right)
            # 左孩子后入栈
            if node.left:
                stack.append(node.left)

完整前序遍历——迭代法

class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        # 根节点为空则返回空列表
        if not root:
            return []
        stack = [root]
        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

2.中序遍历迭代:

前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,要访问的元素和要处理的元素顺序是一致的,都是中间节点,所以刚刚才能写出相对简洁的代码

中序遍历是左中右,先访问的是二叉树顶部的节点,然后层层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),所以处理顺序和访问顺序是不一致的。因而在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

        stack = []  # 不能提前将root节点加入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	

完整中序遍历——迭代法

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:

        if not root:
            return []
        stack = []  # 不能提前将root节点加入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

3.后序遍历迭代

后序遍历是“左右中”,前序遍历是“中左右”——>"中右左"——>翻转result数组:“左右中”。因此可以修改前序遍历得到后序遍历

        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]

#代码顺序里是中左右,因为栈是先进后出,可以发现与前序遍历的区别在于这四行的顺序
       #     if node.left:
       #        stack.append(node.left)
            # 右孩子后入栈
       #     if node.right:
       #         stack.append(node.right)

完整的后序遍历迭代法:

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]