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

数据结构:堆和二叉树

完全二叉树

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

例如:

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− 1和h=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− 1和h=log2(n+ 1)
T(n) =n−log2(n+ 1) ≈n
向下调整算法建堆时间复杂度为:O(n)
为什么向下调整算法比向上调整算法块?
因为向下调整算法下面的层节点多,移动次数少。而向上调整算法下面的层节点多,移动次数也多。

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


Top-K问题

最优解是用堆排序。

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

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

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

http://www.cnnetsun.cn/news/94954.html

相关文章:

  • Obsidian Style Settings插件使用指南:打造个性化笔记界面
  • Swagger2Word终极指南:一键将API文档转为专业Word格式
  • 【C2000中断Debug】如何定位与调试异常中断
  • vue3中computed计算属性和方法的区别
  • LobeChat国际社区动态:全球开发者共同维护
  • 基于STM32的水质检测系统设计与实现
  • Radm1n1ster CN
  • 重构智慧书-第18条:实力与实干
  • 读捍卫隐私08智能出行
  • 媒体专访实录:LobeChat创始人谈开源初心
  • 小喵播放器 1.1.2| 一款支持视频超分的播放器,支持网页视频以及B站番剧
  • LobeChat待办事项提取与提醒功能实现
  • LobeChat会话管理机制揭秘:让每一次对话都井然有序
  • JS利用分片技术实现大文件分块上传的性能优化?
  • HTML5配合AES加密实现大文件分块传输安全?
  • NPP 热带森林:墨西哥查梅拉,1982-1995 年,R1
  • WordPress粘贴微信公众号内容自动排版
  • 毕设 stm32与深度学习口罩佩戴检测系统(源码+硬件+论文)
  • 手机端AIDE安卓音乐播放器软件代码
  • 如何在 Windows 11/10 中启用IE浏览器?恢复 Internet Explorer 一键搞定,就这么简单!
  • Scholar Inbox 订阅最新学术进展至邮箱
  • D.二分查找-二分答案-求最小——1283. 使结果不超过阈值的最小除数
  • A.每日一题——3562. 折扣价交易股票的最大利润
  • 圣默思 Teledyne DalsaFilr SWIR相机
  • Go 语言结构
  • JavaScript for 循环详解
  • 5步搞定SillyTavern版本升级:告别烦恼的完整指南
  • 猫头虎AI开源分享:如何批量获取稀土掘金社区文章阅读量暨文章阅读量数据批量提取解决方案
  • DBO-RBF多变量回归预测 优化宽度+中心值+连接权值 (多输入单输出)Matlab代码
  • 亲测!WordPress网站接入聚合登录实践