← 返回软件技术总览 软件技术 · 知识点深化 · 堆与优先队列:大顶堆小顶堆、堆排序、TopK
知识点深化 · 数据结构 · 堆与优先队列

堆与优先队列:大顶堆小顶堆、堆排序、TopK

堆是一棵完全二叉树,且满足"父节点总 ≥(或≤)孩子"。它能 O(log n) 地取出最值,是优先队列、TopK、任务调度的底层。这一页把大顶堆/小顶堆的数组表示、上浮下沉、堆排序和 TopK 讲透。

① 小白第一课怎么学(4 步走,约 60 分钟)

别急着背代码,先按这四步建立直觉:

1看图建立直觉(10 分钟)
读②③:想象堆是"最值永远在根"的完全二叉树。
2记数组表示(15 分钟)
读④:i 的孩子在 2i+1/2i+2,上浮下沉。
3手推堆操作(20 分钟)
精读⑤:插入上浮、删根下沉、堆排序。
4刷题纠错(15 分钟)
做⑦⑩,错题回⑥。
本课小目标学完你要能:① 说出大顶堆/小顶堆定义;② 用数组父子下标公式;③ 解释 TopK 为什么用小顶堆。

② 一图看懂:堆与优先队列全地图

堆 Heap 大顶堆 父≥子,根是最大值 小顶堆 父≤子,根是最小值 数组表示 i 孩子=2i+1/2i+2 应用:TopK/优先队列/堆排 O(n log n) 易错:上浮下沉方向反 TopK 用小顶堆
读法:中心是堆,上是大顶/小顶,右是数组表示,下是应用 TopK 与易错。

③ 本质直觉:堆就是"最值永远蹲在根上"的完全二叉树

堆的两条铁律:① 它是完全二叉树(每层填满,最后一层靠左);② 大顶堆每个父节点 ≥ 两个孩子,小顶堆每个父节点 ≤ 孩子。所以根永远是最值。

用数组存:因为完全二叉树形状规整,直接存在数组里。下标 i 的左孩子在 2i+1,右孩子在 2i+2,父节点在 (i-1)/2。

两个核心动作:新元素加到末尾,若比父大(大顶堆)就上浮 swap;删根时把末尾元素搬到根,再一路下沉和较大的孩子交换。都是 O(log n)。

9 6 8 3 2 大顶堆:根 9 是最大值 数组:[9,6,8,3,2]
为什么 TopK 用小顶堆要找最大的 K 个数,维护一个大小为 K 的小顶堆:堆顶是当前 K 个里最小的。新数来了比堆顶大就替换堆顶再下沉——最后堆里就是最大 K 个。时间 O(n log K),比全排序 O(n log n) 省。

④ 完整体系与对比表

核心操作复杂度

操作说明复杂度
建堆从最后一个非叶子节点下沉O(n)
插入放末尾再上浮O(log n)
取堆顶直接 arr[0]O(1)
删堆顶末尾换根再下沉O(log n)
堆排序反复取堆顶O(n log n)

父子下标公式

数组下标关系(0 起)左孩子 = 2i+1,右孩子 = 2i+2,父 = (i-1)/2

堆排序三步走

① 建大顶堆:从最后一个非叶子节点 (n/2−1) 往前逐个下沉;② 交换:把堆顶(最大值)和末尾元素交换;③ 下沉:堆大小减 1,对新堆顶下沉。重复②③直到堆空。结果从小到大排序。

⑤ 用法场景与典型例题

例1(数组对应)堆数组 [9,6,8,3,2],下标 1 的孩子是哪两个?
2i+1 和 2i+2。
i=1:左=2×1+1=2(值8),右=2×1+2=3(值3)。即节点 6 的孩子是 8 和 3。
例2(TopK)从 100 万个数找最大 100 个,用什么堆?
大小 K=100 的小顶堆。
维护小顶堆,堆顶是当前 100 个里最小的。遍历每个数:比堆顶大就替换并下沉。O(n log 100)。答案:小顶堆(找最大 K 用小顶堆)。
例3(堆排序)大顶堆反复取堆顶得到什么序?
堆顶是最大值,换到末尾。
每次把最大值换到数组末尾,剩余部分重新堆化。最终数组从前往后是升序。
做题心法找最大 K 用小顶堆,找最小 K 用大顶堆——和直觉相反,记"堆顶是要被淘汰的那个"。

⑥ 高频错误诊断(4 条)

错误1:TopK 堆选反找最大 K 要用小顶堆(堆顶最小,方便淘汰),不是大顶堆。
错误2:上浮下沉方向搞反大顶堆:孩子比父大才上浮/下沉交换;小顶堆相反。别把大小关系写反。
错误3:建堆从根开始建堆要从最后一个非叶子节点往前下沉,从根开始会多做无用功。
错误4:以为堆是有序数组堆只保证父子关系,兄弟之间无序,不是排序数组。

⑦ 考点真题演练(4 题)

考点分布

考法出题形式应对
堆性质问根是什么大顶堆根最大,小顶堆根最小
下标公式i 的孩子位置2i+1 / 2i+2
TopK找最大 K 用什么堆小顶堆 O(n log K)
堆排序复杂度/结果O(n log n),升序

真题基础1. 大顶堆的根节点存储的是?

真题中档2. 数组下标 i 的左孩子下标是(0 起始)?

真题中档3. 从海量数据中求最大的 K 个数,应维护?

真题拔高4. 堆排序的时间复杂度是?

⑧ 必背知识点卡

大顶堆:父≥子,根最大 升序堆排
小顶堆:父≤子,根最小 TopK
下标:左 2i+1,右 2i+2,父 (i-1)/2
插入:末尾加,比父大上浮 O(log n)
删顶:末尾换根,下沉 O(log n)
建堆:从最后非叶子节点下沉 O(n)
TopK:找最大 K 用小顶堆 O(n log K)

⑨ 应用输出:设计一个任务优先级调度器

场景:操作系统有多个任务按优先级执行,每次选优先级最高的运行。
① 选型:优先队列底层用大顶堆,优先级最高的任务永远在堆顶。
② 新任务到达:插入堆,上浮到正确位置 O(log n)。
③ 调度:取堆顶执行最高优先级任务,删除堆顶(末尾换根下沉)O(log n)。
④ 动态改优先级:更新节点值后重新上浮/下沉。
⑤ 效果:不用全排序,O(log n) 就能拿到最值。
口述思路合上书说:"优先级调度就是大顶堆,堆顶永远是最高优先级任务。"

⑩ 分层练习(基础 + 中档 + 拔高)

▍基础 6 题

基础1堆是完全二叉树吗?
是。
基础2大顶堆根是最大还是最小?
最大。
基础3i 的父节点下标?
(i-1)/2。
基础4取堆顶复杂度?
O(1)。
基础5插入堆要做什么动作?
末尾加,再上浮。
基础6删堆顶要做什么?
末尾换根,再下沉。

▍中档 6 题

中档7找最小 K 个数用什么堆?
大顶堆(堆顶是 K 个里最大的,方便淘汰)。
中档8建堆时间复杂度?
O(n),不是 O(n log n)。
中档9堆排序为什么不稳定?
交换跨度大,相等元素相对顺序可能变。
中档10优先队列底层通常是什么?
堆(Java PriorityQueue 是小顶堆)。
中档11下沉时大顶堆要和哪个孩子交换?
两个孩子中较大的那个。
中档12堆适合频繁取最值吗?
适合,取堆顶 O(1),调整 O(log n)。

▍拔高 6 题

拔高13为什么建堆是 O(n) 而不是 O(n log n)?
大部分节点在底层下沉路径短,总和收敛于 O(n)。
拔高14数据流中位数怎么求?
两个堆:大顶堆存较小半、小顶堆存较大半,动态平衡。
拔高15堆和 BST 的区别?
堆只要父子有序,取最值 O(1);BST 全序但插入 O(log n) 且结构可能歪。
拔高16为什么 TopK 用堆而不是全排序?
只关心 K 个最值,O(n log K) 远小于 O(n log n)。
拔高17下沉 vs 上浮哪个在建堆用?
建堆用下沉(从后往前),插入用上浮。
拔高18堆排序空间复杂度?
原地 O(1),但不稳定。

⑪ 记忆口诀 + 7 天复习计划

三句口诀① 堆是完全二叉树,父子定大小。② 左 2i+1 右 2i+2,插入上浮删顶下沉。③ 找最大 K 用小顶堆,建堆 O(n) 排 O(n log n)。
天任务自检
第 1 天读②③④,画堆数组对应图父子下标算对
第 2 天背操作表 + 基础 1-6复杂度全对
第 3 天做中档 7-12,手写下沉步骤方向不反
第 4 天做拔高 13-18,推中位数双堆能讲清平衡
第 5 天做⑦真题 4 题限时每题 2 分钟
第 6-7 天合上书口述口诀,默写 TopK 思路不看资料全默对

← 返回软件技术总览