Skip to content

树与堆

树与堆都属于非线性结构。树强调递归、层级关系和子问题建模;堆强调“局部最值”的快速维护。它们经常出现在遍历、搜索、优先级调度和 top-k 问题里。

概念

  • 树处理的是层级关系和子问题拆分,堆处理的是局部最值维护。
  • 树题很多时候不是直接算答案,而是先定义递归函数返回什么。
  • 堆题很多时候不是排序,而是持续维护当前最值或 top-k。

怎么处理

  1. 树题先判断是遍历问题、路径问题还是递归返回值问题。
  2. 写递归前先说清函数语义和返回值含义。
  3. 如果题目不断要求“当前最小 / 最大 / 前 k 个”,优先想堆。
  4. 如果题目涉及连接关系变化,再判断是不是并查集或 Trie 这类扩展结构。

树递归的两种思维(看到树题先在这两个里选)

所有二叉树递归题本质都能划进这两类思维,选错会让代码复杂度反常增加

思维何时用代码骨架典型题
分解法(后序 / “你给我,我给你”)当前节点的答案 = f(左子树答案, 右子树答案)先递归左右获取结果,再合并最大深度、直径、判是否平衡、合并二叉树
遍历法(前序 + 外部状态)必须携带路径/父亲/深度等路上信息进递归前更新状态,退出时回溯路径总和、路径打印、反转二叉树

快速判断口诀:

  • 问“整棵树的某个指标” → 分解法(递归返回值就是子问题答案)
  • 问“从根到某节点 / 某些路径 / 与祖先有关的信息” → 遍历法(递归函数返回 void,靠全局变量收集)
  • 两者可以混用,但先选一个主调

典型实例

专题先看什么
二叉树先把遍历、递归和层序处理讲清楚
二叉搜索树看有序性如何减少搜索范围
堆与优先队列看 top-k 和局部最值如何维护
Trie 字典树看前缀问题如何建模
并查集看连通性问题如何处理

工程实战题

专题先看什么
数据流中位数(工程)双堆配合 — 金融/监控 p50/p99 分位数场景
跳表 SkipList(工程)Redis ZSet / ConcurrentSkipListMap / LevelDB MemTable 的核心
Radix Tree(压缩 Trie,工程)URL / IP 路由表等工程场景为何不用裸 Trie
Merkle Tree(工程)Git / 区块链 / IPFS / S3 / Dynamo 反熵的底层
搜索自动补全 LC642(工程)Trie + Top-K + 频次——谷歌搜索框 / IDE 补全 / Lucene Suggester 统一底层
任务调度器 LC621+Cron(工程)贪心 + 堆桌面 + 时间轮 + 分布式(Quartz / XXL-Job / Airflow)
撮合引擎(工程)交易所订单簿,Price-Time Priority 核心结构

看到什么就先想到这类

  • 出现“父子层级、路径、子树、遍历”。
  • 出现“前 k 个、实时最小 / 最大”。
  • 出现“前缀匹配、集合合并、连通块”。