news 2026/5/12 14:02:12

数据结构:堆和二叉树

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据结构:堆和二叉树

完全二叉树

完全二叉树是一种特殊的二叉树结构,所有层(除最后一层外)的节点都完全填满,且最后一层的最后一层节点尽可能从左到右连续排列

例如:

1 / \ 2 3 / \ / 4 5 6

只分为小顶堆和大顶堆。

小顶堆和大顶堆

小顶堆是一种完全二叉树,每个父节点的值小于或等于其子节点的值。

1 / \ 3 2 / \ / 4 6 5 [1,3,2,4,6,5]

大顶堆也是一种完全二叉树,每个父节点的值大于或等于其子节点的值。

9 / \ 7 5 / \ / 4 6 3 [9,7,5,4,6,3]

向上调整和向下调整(单次调整)

典型的例子就是堆的尾增首删。(尾删很容易,直接删最后一个数据)

堆的尾增:向上调整

堆的尾增操作通常指在堆的末尾插入新元素后,通过向上调整(Heapify Up)维护堆的性质。

第一步:插入元素到末尾
将新元素插入堆的最后一个位置(数组末尾),保持完全二叉树的结构。

第二步:向上比较交换
从插入位置开始,比较当前节点与其父节点的值。大顶堆时,若当前节点值大于父节点值(小顶堆则是小于),则交换两者位置,并继续向上比较,直到满足堆的性质或到达根节点。

时间复杂度:
最坏情况下需从叶子节点调整到根节点,复杂度为O(log N)


逐步演示:

现在有小顶堆:

1 / \ 3 5 / \ / 4 8 6 [1, 3, 5, 4, 8, 6]

插入新元素:在堆末尾插入元素2

1 / \ 3 5 / \ / \ 4 8 6 2 [1, 3, 5, 4, 8, 6, 2]

向上调整,比较新节点与父节点:由于2 < 5,不满足最小堆性质,交换两者。

1 / \ 3 2 / \ / \ 4 8 6 5 [1, 3, 2, 4, 8, 6, 5]

继续判断,比较其与新的父节点:由于2 > 1,满足最小堆性质,停止交换。算法终止。


堆的首删:向下调整

堆的首删操作通常指删除堆顶元素后,通过向下调整(Heapify Down)维护堆的性质。

第一步:交换并删除堆顶元素

将堆顶元素(根节点)与堆的最后一个元素交换位置,随后删除末尾元素(原堆顶)。保持完全二叉树的结构。

第二步:向下比较交换

从新的堆顶开始,比较当前节点与其左右子节点的值。大顶堆时,若当前节点值小于较大子节点值(小顶堆则是大于),则交换两者位置,并继续向下比较,直到满足堆的性质或到达叶子节点。

时间复杂度:
最坏情况下需从根节点调整到叶子节点,复杂度为O(log N)。


逐步演示(小顶堆)

初始堆:

1 / \ 3 5 / \ / 4 8 6 [1, 3, 5, 4, 8, 6]

删除堆顶元素:

1.交换堆顶(1)与末尾元素(6):

6 / \ 3 5 / \ 4 8 [6, 3, 5, 4, 8]

2.向下调整:
比较新堆顶(6)与左右子节点(3和5),选择较小子节点(3)。
由于6 > 3,交换两者:

3 / \ 6 5 / \ 4 8 [3, 6, 5, 4, 8]

继续调整节点6:比较其与子节点(4和8),选择较小子节点(4)。
由于6 > 4,交换两者:

3 / \ 4 5 / \ 6 8 [3, 4, 5, 6, 8]

节点6无子节点,调整终止,算法结束。


向上调整建堆

是一种将无序数组转换为堆结构的方法。其核心思想是从第二个节点开始,逐步向后调整每个子树,即反复使用上文的单次的向上调整,使其满足堆的性质(最大堆或最小堆)。

目标:大顶堆 5 / \ 3 6 / \ / \ 7 5 1 9 从3开始调整,然后是6 7 5 1 9。 3不用调整,6要调整 6 / \ 3 5 / \ / \ 7 5 1 9 7要调整 9 / \ 6 7 / \ / \ 3 5 1 5 9要调整,已经是最后一位,算法结束。

时间复杂度:

分析:
第1层,2^0个结点,需要向上移动0层
第2层, 2^1 个结点,需要向上移动1层
第3层, 2^2 个结点,需要向上移动2层
第4层, 2^3 个结点,需要向上移动3层
......
第h层, 2^h−1个结点,需要向上移动h-1层
则需要移动结点总的移动步数为:每层结点个数 * 向上调整次数(第⼀层调整次数为0)
T(h) = 2^1 ∗ 1 + 2^2 ∗ 2 + 2^3 ∗ 3 + .. + 2^h−2∗ (h− 2) + 2^h−1∗ (h− 1)
数学计算得:
T(h) = −(2^​​​​​​​h− 1) + 2^​​​​​​​h∗ (h− 1) + 2^0
根据⼆叉树的性质:n= 2h− 1h=log2(n+ 1)
T(n) = −N+ 2^​​​​​​​h∗ (h− 1) + 2^0
F(h) = 2^h(h− 2) + 2
F(n) = (n+ 1)(log(n+ 1) − 2) + 2
由此可得:
向上调整算法建堆时间复杂度为:O(nlogn)

向下调整建堆

是一种将无序数组转换为堆结构的方法。其核心思想是从最后一个非叶子节点开始,逐步向前调整每个子树,即反复使用上文的单次的向下调整,使其满足堆的性质(最大堆或最小堆)。

目标:大顶堆 5 / \ 3 6 / \ / \ 7 5 1 9 从6开始调整,然后是3,5。 6要调整,6和子节点1,9都比较,最终选择和9交换 5 / \ 3 9 / \ / \ 7 5 1 6 3要调整 5 / \ 7 9 / \ / \ 3 5 1 6 5要向下调整两次 9 / \ 7 6 / \ / \ 3 5 1 5 已经是第一位,算法结束。

时间复杂度:

第1层,2^0个结点,需要向下移动h-1层
第2层, 2^1 个结点,需要向下移动h-2层
第3层, 2^2 个结点,需要向下移动h-3层
第4层, 2^3 个结点,需要向下移动h-4层
......
第h-1层, 2^h−2个结点,需要向下移动1层
则需要移动结点总的移动步数为:每层结点个数 * 向下调整次数
T(h) = 20∗ (h− 1) + 21∗ (h− 2) + 22∗ (h− 3) + 23∗ (h− 4) + .. + 2h−3∗ 2 + 2h−2∗ 1
由数学计算:
T(h) = 2^h− 1 −h
根据⼆叉树的性质:n= 2^h− 1h=log2(n+ 1)
T(n) =nlog2(n+ 1) ≈n
向下调整算法建堆时间复杂度为:O(n)
为什么向下调整算法比向上调整算法块?
因为向下调整算法下面的层节点多,移动次数少。而向上调整算法下面的层节点多,移动次数也多。

如果有已给定的数组,一般使用向下调整建堆。


Top-K问题

最优解是用堆排序

比如:找到全国最富有的十个人。

第一步:用任意10人建小顶堆 → 次数可忽略(≈常数)

第二步:遍历剩余 14亿-10 人,逐个判断调整
和堆顶比,如果比顶堆大,那就是比第十名富有,第十名要淘汰,而他要插进去(替换堆顶+向下调整)
​第三步:全部比完后,留在堆中就是最富有的十个人。
时间复杂度:O(nlogK)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 23:05:17

LobeChat 360搜索推广策略

LobeChat&#xff1a;构建私有化AI交互入口的技术实践 在生成式AI浪潮席卷各行各业的今天&#xff0c;一个现实问题摆在开发者和企业面前&#xff1a;如何在享受大语言模型强大能力的同时&#xff0c;不牺牲数据安全与系统可控性&#xff1f;市面上的主流对话产品虽然体验流畅&…

作者头像 李华
网站建设 2026/5/10 22:51:31

LobeChat表单插件开发入门:为AI添加结构化输入

LobeChat表单插件开发入门&#xff1a;为AI添加结构化输入 在智能客服、企业助手和自动化工作流日益普及的今天&#xff0c;我们越来越依赖大语言模型&#xff08;LLM&#xff09;来处理复杂任务。然而&#xff0c;一个普遍存在的问题是&#xff1a;尽管模型“懂语言”&#xf…

作者头像 李华
网站建设 2026/5/11 0:14:49

Auto-Coder新特性SubAgents 融合里面提到的两个概念:subagents 和 workflow国内能够访问吗?(唐突了,原来这是两个AI编程的核心概念)

SubAgents 融合/Code agent 成本控制大法 问题&#xff1a;Auto-Coder新特性SubAgents 融合里面提到的两个概念&#xff1a;subagents 和 workflow国内能够访问吗&#xff1f; 唐突了&#xff0c;原来这是两个技术概念&#xff1a; Sub-agents和Workflow作为AI编程的核心概念…

作者头像 李华