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

算法学习记录03——二叉树学习笔记:从两道题看透后序位置的关键作用​

最近在啃二叉树的知识点,过程中遇到两个看似简单的小问题,却让我对二叉树遍历里的「后序位置」有了新的理解。今天就把这个思考过程记录下来,方便以后回头看,也希望能给同样在学二叉树的朋友。

先从两个基础问题说起

刚开始练手的时候,我先后碰到了两道题,题面都很直白:​

  1. 给一棵二叉树,打印出每个节点所在的层数(根节点算第 1 层);​
  2. 给一棵二叉树,计算出每个节点作为根的子树,包含多少个节点(比如叶子节点的子树节点数就是 1)。​

本来以为都是常规遍历题,结果写的时候发现,这两道题的处理逻辑居然差了不少 —— 而这个差异,恰好指向了二叉树遍历中一个很重要的点。​

问题 1:打印节点层数 —— 遍历过程中就能 “顺带” 解决​

先看第一题,打印节点层数。其实稍微想一下就知道,根节点是第 1 层,那根节点的左右孩子就是第 2 层,孩子的孩子就是第 3 层…… 这个层数是 “自上而下” 传递的。​

所以写代码的时候,用前序、中序、后序遍历其实都能做。比如用前序遍历的话,思路是这样的:​

  1. 访问当前节点时,先把当前的层数记录下来(比如直接打印);​
  2. 递归遍历左孩子时,把层数 + 1 传过去;​
  3. 递归遍历右孩子时,同样把层数 + 1 传过去。​
    核心代码大概长这样(用 Python 举个例子):
def print_level(root, level):if root is None:return# 先访问当前节点,打印层数print(f"节点{root.val},层数:{level}")# 递归左孩子,层数+1print_level(root.left, level + 1)# 递归右孩子,层数+1print_level(root.right, level + 1)# 调用的时候,根节点层数是1
print_level(root, 1)

你看,这里的层数信息,是在遍历到父节点的时候,直接传递给子节点的。不需要等子节点处理完,当前节点的层数在 “访问它的时候” 就已经确定了 —— 完全是 “顺带” 解决的事。​

问题 2:统计子树节点数 —— 必须等子树遍历完才能算​

再看第二题,统计每个节点的子树节点数。这时候就发现,事情不一样了。​

比如现在有个节点 A,它有左孩子 B 和右孩子 C。要算 A 的子树节点数,得先知道 B 的子树有多少节点,再知道 C 的子树有多少节点,最后加上 A 自己(1 个),才能得到 A 的子树节点数。​

也就是说,必须先遍历完当前节点的左右子树,才能计算当前节点的结果。​

这时候就不能用前序遍历了 —— 如果前序遍历先访问 A,这时候 B 和 C 的子树还没遍历,根本不知道它们的节点数,怎么算 A 的?​
这时候就得用到后序遍历了。后序遍历的顺序是:左子树 → 右子树 → 当前节点。刚好符合 “先处理完子树,再处理当前节点” 的需求。​

同样用 Python 写核心代码,思路是这样的:​

  1. 递归计算左子树的节点数;​
  2. 递归计算右子树的节点数;​
  3. 当前节点的子树节点数 = 左子树节点数 + 右子树节点数 + 1(自己);​
  4. 返回当前节点的子树节点数(供父节点使用)。​

代码大概是这样:

def count_subtree_nodes(root):if root is None:# 空节点的子树节点数是0return 0# 先算左子树节点数left_count = count_subtree_nodes(root.left)# 再算右子树节点数right_count = count_subtree_nodes(root.right)# 后序位置:处理当前节点,计算子树节点数current_count = left_count + right_count + 1print(f"节点{root.val}的子树节点数:{current_count}")# 返回当前节点的子树节点数,给父节点用return current_count# 调用的时候,从根节点开始
count_subtree_nodes(root)

这里的关键是 “返回值” 和 “后序位置”。当前节点的结果,依赖于左右子树的结果,而左右子树的结果只能通过递归的返回值拿到 —— 只有等左右子树都遍历完(后序位置),才能计算当前节点的结果。​

对比之后:后序位置的核心特点 —— 能拿到子树的信息​
把这两道题放在一起对比,就能很明显地看出后序位置的作用了:​

  • 像 “节点层数” 这种不需要子树信息的问题,前序、中序、后序都能做,因为信息是 “自上而下” 传递的;​
  • 但像 “子树节点数” 这种需要子树信息的问题,只能靠后序位置 —— 因为只有后序位置,才能通过递归返回值,拿到左子树和右子树处理后的结果。​

换句话说,后序位置的本质,是 “处理当前节点时,左右子树已经处理完毕,能获取到子树的全部信息”。这是前序和中序位置做不到的 —— 前序是没处理子树就先处理当前节点,中序是处理了左子树但没处理右子树(或者反过来,看遍历顺序),都拿不到完整的子树信息。​

一个小总结:遇到 “子树相关” 问题,优先想后序​

练完这两道题,我自己总结了一个小规律:​

以后在做二叉树的题目时,先看题目是不是和 “子树” 有关 —— 比如求子树的节点数、子树的高度、子树的最大值、判断两棵子树是否对称等等。如果是,那大概率要用到后序遍历。​

而且这类题的解题步骤也很固定:​

  1. 先给递归函数定一个明确的 “返回值”—— 比如求子树节点数,返回值就是当前节点子树的节点数;求子树高度,返回值就是当前节点子树的高度;​
  2. 递归处理左子树和右子树,拿到它们的返回值;​
  3. 在后序位置,用左子树和右子树的返回值,计算当前节点的结果;​
  4. 返回当前节点的结果,供父节点使用。​
http://www.dtcms.com/a/511399.html

相关文章:

  • Rust高性能分布式任务调度系统开发实践:从设计到性能优化
  • go tools安装
  • 阿里云代理商:如何给阿里云配置网络ACL?
  • 阿里巴巴 Java 开发手册解读:DO、DTO、BO、AO、VO、Query 的区别与用法
  • 接口测试如何做
  • 记录日常日志
  • 【LeetCode_876_2.02】快慢指针在链表中的简单应用
  • LOOP套LOOP,双LOOP优化,效率提升近30倍
  • iOS 混淆实战 多工具组合完成 IPA 混淆、加固与工程化落地(iOS混淆|IPA加固|无源码混淆|Ipa Guard|Swift Shield)
  • 计算机毕设java中学生心理健康管理系统 中学生心理健康管理的Java平台解决方案 Java技术驱动的中学心理健康管理系统研发
  • 模重复平方计算法
  • 温州网站制作套餐.net网站开发是什么对象开发
  • Tuning——CC调试(适用高通)
  • 【AI智能体开发】什么是LLM?如何在本地搭建属于自己的Ai智能体?
  • Leetcode+Java+图论+并查集
  • 网站代备案流程图越秀网站建设推广
  • 网站 app 公众号先做哪个网站建设实践
  • SpringBoot常用内置工具类使用示例
  • Qt和ffmpeg结合打造gb28181推流/支持udp和tcp被动以及tcp主动三种方式
  • 设计模式-工厂模式:解耦对象创建的设计艺术
  • UVa 1660 Cable TV Network
  • 使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 20--PO(POM) 设计模式和用例撰写
  • 网站建设年度计划申请了域名 网站怎么建设呢
  • 《黄雀》电视剧总结
  • 云计算与服务器概述
  • 【Java Web学习 | 第1篇】前端 - HTML
  • Jenkins流水线项目发布
  • 网站优化需要做什么烟台网站建设比较大的
  • CAN入侵检测系统IDS不行,用扩充白名单机制保证汽车功能安全需求
  • 微软Teams的Media bypass的介绍