当前位置: 首页 > news >正文

LeetCode94.二叉树的中序遍历、LeetCode144. 二叉树的前序遍历、LeetCode145. 二叉树的后序遍历

文章目录

  • 二叉树的中序遍历
    • 递归算法
      • 1.代码实现
      • 2. 基本概念
      • 3. 算法结构
      • 4. 关键要素
        • 4.1 递归终止条件
      • 5. 算法特点
        • 5.1 时间复杂度
        • 5.2 空间复杂度
        • 5.3 递归调用栈
      • 6. 递归与迭代的对比
      • 7.实例演示递归序
        • 7.1递归序完整周期分析
        • 7.2关键观察
        • 7.3总结
    • 迭代算法
      • 1.代码实现
      • 2.算法原理
      • 3.执行步骤详解
      • 4.关键点解析
      • 5.优势与适用场景
    • 递归实现 vs 迭代实现的核心区别
      • 递归实现中的栈操作时机
      • 迭代实现中的栈操作时机
    • 为什么会有这种差异?
  • 二叉树的前序遍历
    • 递归代码实现
    • 迭代代码实现
  • 二叉树的后序遍历
    • 递归代码实现
    • 迭代代码实现

二叉树的中序遍历

递归算法

1.代码实现

    def inorderTraversal(self, root):"""二叉树中序遍历(递归实现)参数:root: 二叉树根节点返回:List[int]: 中序遍历结果列表"""result = []def inorder(node):"""递归辅助函数"""if not node:return# 遍历左子树inorder(node.left)# 访问根节点result.append(node.val)# 遍历右子树inorder(node.right)inorder(root)return result

2. 基本概念

  • 中序遍历 :按照"左子树 → 根节点 → 右子树"的顺序访问二叉树节点
  • 递归思想 :将问题分解为规模更小的同类问题,直到达到基本情况

3. 算法结构

def inorder(node):if not node:return# 1. 遍历左子树inorder(node.left)# 2. 访问根节点result.append(node.val)# 3. 遍历右子树inorder(node.right)

4. 关键要素

4.1 递归终止条件
if not node:return
  • 当节点为空时,直接返回,这是递归的终止条件
  • 防止无限递归,确保算法能够正常结束 3.2 递归调用顺序
  1. 先递归左子树 : inorder(node.left)

    • 先处理左子树的所有节点
    • 左子树处理完成后,才会执行后续代码
  2. 访问根节点 : result.append(node.val)

    • 将当前节点的值添加到结果列表中
    • 这是中序遍历的"中"部分
  3. 后递归右子树 : inorder(node.right)

    • 处理右子树的所有节点
    • 这是递归的最后一步

5. 算法特点

5.1 时间复杂度
  • O(n) :每个节点只被访问一次,n为节点数量
5.2 空间复杂度
  • O(h) :h为二叉树的高度
  • 递归调用栈的深度取决于树的高度
  • 最坏情况下(树退化为链表),空间复杂度为O(n)
5.3 递归调用栈
  • 每次递归调用都会在调用栈中创建一个新的栈帧
  • 栈帧中保存了当前节点的信息和返回地址
  • 递归返回时,从栈帧中恢复执行状态

6. 递归与迭代的对比

在这里插入图片描述
递归实现直接对应中序遍历的定义,代码简洁明了,但可能会因为递归深度过大导致栈溢出。在实际应用中,对于深度较大的树,可以考虑使用迭代实现。

7.实例演示递归序

用文字和表格展示完全二叉树 [4, 2, 6, 1, 3, 5, 7] 的递归序完整周期。

       4/   \2     6/ \   / \1   3 5   7
7.1递归序完整周期分析

第一阶段:递归进入(沿左子树向下)
在这里插入图片描述
第二阶段:处理节点2及其右子树
在这里插入图片描述
第三阶段:处理根节点4及其右子树
在这里插入图片描述

7.2关键观察
  1. 节点访问顺序 :1 → 2 → 3 → 4 → 5 → 6 → 7(中序遍历结果)
  2. 最大递归深度 :3(树的高度)
  3. 最大栈大小 :3(节点4、2、1同时在栈中)
  4. 每个节点的处理模式 :
    • 调用(入栈)
    • 访问(处理节点值)
    • 返回(出栈)
  5. 递归序特点 :
    • 先沿左子树一直向下到最深处
    • 然后按"左-根-右"顺序访问节点
    • 最后逐层返回
7.3总结

这个完整周期展示了递归中序遍历的三个关键阶段:

  1. 递归进入 :从根节点开始,沿左子树一直向下
  2. 节点处理 :按中序顺序访问节点(左-根-右)
  3. 递归退出 :处理完节点后逐层返回
    通过这个表格,我们可以清晰地看到递归调用栈的动态变化,以及每个节点在何时被调用、访问和返回。

迭代算法

1.代码实现

    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:"""  # 修正:缩进与函数内部代码一致(4个空格)二叉树中序遍历(迭代实现)参数:root: 二叉树根节点返回:List[int]: 中序遍历结果列表"""result = []  # 缩进与文档字符串对齐,属于函数内部代码块stack = []current = root# 使用栈模拟递归过程:先遍历所有左子节点,再访问根节点,最后遍历右子节点while current or stack:# 1. 将当前节点及其所有左子节点入栈(先处理左)while current:stack.append(current)current = current.left# 2. 弹出栈顶节点,加入结果列表(处理中)current = stack.pop()result.append(current.val)# 3. 转向右子节点(处理右)current = current.rightreturn result

2.算法原理

迭代实现使用 栈 来模拟递归过程,避免了递归调用带来的系统开销。中序遍历的顺序是"左-根-右",迭代实现的关键是:

  1. 先访问最左边的节点 :通过不断向左移动并将节点入栈
  2. 访问栈顶节点 :当到达最左边时,弹出栈顶节点并访问
  3. 转向右子树 :访问完当前节点后,转向其右子树继续遍历

3.执行步骤详解

以二叉树 [4, 2, 6, 1, 3, 5, 7] 为例:

       4/   \2     6/ \   / \1   3 5   7
初始状态
- result = []
- stack = []
- current = root(4) 执行过程

在这里插入图片描述

4.关键点解析

  1. 外层循环条件 : while current or stack
    • 只要当前节点不为空或栈不为空,就继续遍历
    • 这确保了所有节点都能被访问到
  2. 内层循环 : while current
    • 将当前节点及其所有左子节点入栈
    • 直到到达最左边的叶子节点
  3. 节点访问 :
    • 弹出栈顶节点(最左边的未访问节点)
    • 访问该节点(将其值加入结果列表)
    • 转向其右子树继续遍历

5.优势与适用场景

  1. 优势 :
    • 避免了递归深度过大导致的栈溢出
    • 没有函数调用的额外开销
    • 可以更好地控制内存使用
  2. 适用场景 :
    • 树的深度可能很大,递归可能导致栈溢出
    • 对性能要求较高的场景
    • 需要精确控制内存使用的环境
      这种迭代实现是二叉树遍历的经典算法,通过栈结构巧妙地模拟了递归过程,实现了与递归相同的效果,但避免了递归的潜在问题。

递归实现 vs 迭代实现的核心区别

递归实现中的栈操作时机

在递归实现中:

  • 调用(入栈) :执行 inorder(node) 时立即入栈
  • 访问节点 :执行 result.append(node.val) 时,节点 仍然在栈中
  • 返回(出栈) :整个函数执行完毕(包括左子树、访问节点、右子树)后才出栈
    因此,在递归序的步骤6中:
  • 操作类型是 访问 节点1
  • 此时节点1 尚未返回 ,所以仍然在调用栈中
  • 调用栈状态保持为 [4,2,1]
  • 直到步骤9执行 返回 操作时,节点1才会出栈,栈状态变为 [4,2]

迭代实现中的栈操作时机

在迭代实现中:

  • 入栈 :主动将节点压入栈中
  • 出栈 :当需要访问节点时,先将节点弹出栈
  • 访问节点 :在弹出栈之后执行
    所以在迭代实现中,访问节点1的步骤会同时执行出栈操作,栈状态会立即变化。

为什么会有这种差异?

这是因为:

  • 递归实现 :调用栈由系统自动管理,函数执行过程中节点始终在栈中,直到完全执行完毕
  • 递归序 :描述的是递归函数的逻辑执行顺序,区分了"访问节点"和"返回"两个不同阶段
  • 迭代实现 :我们手动管理栈,需要将"出栈"和"访问"合并为一个操作步骤

二叉树的前序遍历

递归代码实现

    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:"""二叉树的前序遍历:param root: 二叉树的根节点:return: 前序遍历的节点值列表"""# 方法一:递归实现result = []def traverse(node):if not node:return# 前序遍历:根节点 -> 左子树 -> 右子树result.append(node.val)traverse(node.left)traverse(node.right)traverse(root)return result

迭代代码实现

    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:"""二叉树的前序遍历:param root: 二叉树的根节点:return: 前序遍历的节点值列表"""       # 方法二:迭代实现if not root:return []result = []stack = [root]  # 使用栈来模拟递归过程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

二叉树的后序遍历

递归代码实现

    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:"""二叉树的后序遍历:param root: 二叉树的根节点:return: 后序遍历的节点值列表"""# 方法一:递归实现result = []def traverse(node):if not node:return# 后序遍历:左子树 -> 右子树 -> 根节点traverse(node.left)traverse(node.right)result.append(node.val)traverse(root)return result

迭代代码实现

    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:"""二叉树的后序遍历:param root: 二叉树的根节点:return: 后序遍历的节点值列表"""      # 方法二:迭代实现"""迭代实现后序遍历的核心思想:1. 使用栈来模拟递归过程2. 后序遍历顺序:左子树 -> 右子树 -> 根节点3. 技巧:先按照根节点 -> 右子树 -> 左子树的顺序遍历,然后反转结果4. 这样可以复用前序遍历的思路,只是调整子节点的入栈顺序"""if not root:return []result = []stack = [root]  # 初始化栈,将根节点压入栈中开始遍历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]
http://www.dtcms.com/a/618901.html

相关文章:

  • 网站开发专业怎么样免费商用图片的网站
  • pdf(攻防世界)
  • 营销策划网站良品铺子网络营销案例
  • 北京电商营销中心佛山选择免费网站优化
  • **论文初稿写作指南2025,提升学术研究质量与效率**
  • 嵌入式开发内存越界问题方案
  • 48 我的地址页面布局
  • 提供网站建设框架100个详情页设计图
  • 14.2 知识蒸馏技术:把大模型能力压缩到小模型
  • 安徽服饰网站建设html 网站开发
  • 什么是 IAP 升级?
  • 网站推广的平台排名wordpress文件类型不支持
  • 7.5、Python-匿名函数lambda
  • 江西冰溪建设集团网站宁夏做网站的
  • 如何在容器化环境中查找和利用漏洞(第三部分)
  • 企业网站运营西安网站建设设计的好公司哪家好
  • STM32 SDIO接口介绍
  • Windows Metro app开发初体验
  • Python中的标识符与保留字
  • 怎么查一个网站是否备案ftp如何导入wordpress 主题
  • IntersectionObserver API
  • 陕西煤业化工建设集团有限公司网站网站建设如何选择良好的服务器
  • 贵阳高端网站开发制作做网站应该画什么图
  • 深入浅出Ansible循环语句:从基础到实践
  • 沧州北京网站建设营销 网站制作
  • 徐州10年网站建设 推广公司wordpress 明星主题
  • 修复Ubuntu系统文件损坏问题:手动fsck指令
  • 手动监控3小时?RPA实时追踪小红书关键词排名,效率提升2000%[特殊字符]
  • 网站怎么做响应式番禺做网站最便宜的哪家公司
  • 创建站点的步骤微信小游戏怎么开发