【数据结构与算法】堆

定义

堆是是一个完全二叉树,其中每个节点的值都大于等于或小于等于其子节点的值。这取决于是最大堆还是最小堆。

  • 小根堆:每个根都小于子节点。

  • 大根堆:每个根都大于子节点。

以下部分图例说明来源:【从堆的定义到优先队列、堆排序】 10分钟看懂必考的数据结构——堆_哔哩哔哩_bilibili

image.png

基本操作

堆的上滤(heapify up)和下滤(heapify down)是用于维护堆的性质的两种重要操作,它们通常在插入和删除元素时被调用。

上滤(Heapify Up)

上滤是指将新插入的元素从底部向上移动,直到满足堆的性质为止。复杂度:O(logn)

当新元素被插入到堆的末尾时,它可能破坏了堆的性质,因为它可能比其父节点更大(对于最大堆)或更小(对于最小堆)。

上滤操作会持续比较新插入节点与其父节点的值,如果满足堆的性质,则停止;否则,交换它们的位置,然后继续向上比较,直到满足堆的性质。

上滤的步骤:

  1. 比较新插入节点与其父节点的值。
  2. 如果新插入节点的值比父节点的值大(对于最大堆)或小(对于最小堆),则交换它们的位置。
  3. 继续向上重复上述步骤,直到满足堆的性质或到达堆的根节点。

JavaScript 实现上滤的示例:

function heapifyUp(heap, index) {let parentIndex = Math.floor((index - 1) / 2);while (index > 0 && heap[index] > heap[parentIndex]) { // 最大堆的情况,若为最小堆则将判断条件改为 heap[index] < heap[parentIndex][heap[index], heap[parentIndex]] = [heap[parentIndex], heap[index]]; // 交换节点值index = parentIndex;parentIndex = Math.floor((index - 1) / 2);}
}

下滤(Heapify Down)

下滤是指将堆顶元素从上向下移动,直到满足堆的性质为止。复杂度:O(logn)

当堆顶元素被删除或替换时,堆的性质可能被破坏,因为新的堆顶元素可能不再满足堆的性质。

下滤操作会持续比较堆顶元素与其子节点的值,如果满足堆的性质,则停止;否则,选择较大(对于最大堆)或较小(对于最小堆)的子节点进行交换,然后继续向下比较,直到满足堆的性质或到达堆的叶子节点。

下滤的步骤:

  1. 比较堆顶元素与其子节点的值,选择较大(对于最大堆)或较小(对于最小堆)的子节点。
  2. 如果堆顶元素比子节点的值小(对于最大堆)或大(对于最小堆),则交换它们的位置。
  3. 继续向下重复上述步骤,直到满足堆的性质或到达堆的叶子节点。

JavaScript 实现下滤的示例:

function heapifyDown(heap, index, size) {let largest = index;const left = 2 * index + 1;const right = 2 * index + 2;if (left < size && heap[left] > heap[largest]) { // 最大堆的情况,若为最小堆则将判断条件改为 heap[left] < heap[largest]largest = left;}if (right < size && heap[right] > heap[largest]) { // 最大堆的情况,若为最小堆则将判断条件改为 heap[right] < heap[largest]largest = right;}if (largest !== index) {[heap[index], heap[largest]] = [heap[largest], heap[index]]; // 交换节点值heapifyDown(heap, largest, size);}
}

在堆中,常见的基本操作包括:

  1. 插入节点: 将新节点插入到堆的末尾,然后通过一系列比较与交换操作,将它与其父节点比较并移动,直到满足堆的性质为止。

  2. 删除节点: 通常是删除堆顶元素。删除后,为了保持堆的性质,将堆的末尾元素移到堆顶,然后通过一系列比较与交换操作,将它与其子节点比较并移动,直到满足堆的性质为止。

  3. 堆化: 将一个无序的数组调整为堆的过程。分为从下往上的“自底向上堆化”和从上往下的“自顶向下堆化”。

建堆

建堆是将一个无序的数组转换成一个堆的过程。

自底向上建堆算法步骤:

  1. 从最后一个非叶子节点开始,逐个向上对每个节点进行下滤操作,确保以该节点为根的子树满足堆的性质。复杂度:O(n)。
  2. 重复步骤 1,直到根节点,即整个数组被转换成一个堆。

JavaScript 实现自底向上建堆的示例:

function heapifyDown(heap, index, size) {let largest = index;const left = 2 * index + 1;const right = 2 * index + 2;if (left < size && heap[left] > heap[largest]) { // 最大堆的情况,若为最小堆则将判断条件改为 heap[left] < heap[largest]largest = left;}if (right < size && heap[right] > heap[largest]) { // 最大堆的情况,若为最小堆则将判断条件改为 heap[right] < heap[largest]largest = right;}if (largest !== index) {[heap[index], heap[largest]] = [heap[largest], heap[index]]; // 交换节点值heapifyDown(heap, largest, size);}
}function buildHeap(arr) {const n = arr.length;// 从最后一个非叶子节点开始,自底向上进行堆化for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {heapifyDown(arr, i, n);}
}let arr = [4, 10, 3, 5, 1];
buildHeap(arr);
console.log(arr); // 输出结果为 [10, 5, 3, 4, 1]

在上面的示例中,buildHeap 函数将数组 [4, 10, 3, 5, 1] 转换成了一个最大堆。它从最后一个非叶子节点(即节点 10)开始,逐个向上对每个节点进行下滤操作,直到根节点。最终,数组变成了 [10, 5, 3, 4, 1],满足了最大堆的性质。

自底向上建堆的时间复杂度为 O(n),其中 n 是数组的长度。这种方法通常比自顶向下建堆更高效,因为它减少了不必要的比较和交换次数。

自顶向下建堆算法步骤:

  1. 从数组的第一个元素开始遍历。复杂度:O(nlogn)。
  2. 将当前元素插入到堆中。
  3. 对插入后的堆进行上滤操作,确保堆的性质被维护。

JavaScript 实现自顶向下建堆的示例:

function heapifyUp(heap, index) {let parentIndex = Math.floor((index - 1) / 2);while (index > 0 && heap[index] > heap[parentIndex]) { // 最大堆的情况,若为最小堆则将判断条件改为 heap[index] < heap[parentIndex][heap[index], heap[parentIndex]] = [heap[parentIndex], heap[index]]; // 交换节点值index = parentIndex;parentIndex = Math.floor((index - 1) / 2);}
}function buildHeap(arr) {const n = arr.length;for (let i = 0; i < n; i++) {heapifyUp(arr, i);}
}let arr = [4, 10, 3, 5, 1];
buildHeap(arr);
console.log(arr); // 输出结果为 [10, 5, 3, 4, 1]

在上面的示例中,buildHeap 函数将数组 [4, 10, 3, 5, 1] 转换成了一个最大堆。它遍历数组中的每个元素,并将每个元素插入到堆中,并调用 heapifyUp 函数来确保堆的性质。最终,数组变成了 [10, 5, 3, 4, 1],满足了最大堆的性质。

自顶向下建堆的时间复杂度为 O(nlogn),其中 n 是数组的长度。尽管这种方法不如自底向上建堆的效率高,但它仍然是一种有效的方法来构建堆。

堆排序

堆排序是一种利用堆的性质进行排序的算法。基本思路是先建立一个最大堆,然后逐步将堆顶元素与末尾元素交换,并将交换后的堆调整为最大堆,最终得到一个有序数组。以下是 JavaScript 实现:

function heapSort(arr) {// 建立最大堆heapify(arr);let n = arr.length;// 逐步将堆顶元素与末尾元素交换,并调整堆for (let i = n - 1; i > 0; i--) {// 将堆顶元素与末尾元素交换[arr[0], arr[i]] = [arr[i], arr[0]];// 调整堆heapifyDown(arr, 0, i);}
}let arr = [4, 10, 3, 5, 1];
heapSort(arr);
console.log(arr); // 输出结果为 [1, 3, 4, 5, 10]

优先队列

优先队列是一种数据结构,支持插入和取出具有优先级的元素。在堆的基础上,我们可以实现一个最大堆来构建优先队列。JavaScript 中可以通过堆来实现优先队列。

class PriorityQueue {constructor() {this.heap = [];}// 插入元素insert(val) {this.heap.push(val);this.heapifyUp();}// 取出优先级最高的元素extractMax() {if (this.isEmpty()) {return null;}const max = this.heap[0];const last = this.heap.pop();if (this.heap.length > 0) {this.heap[0] = last;this.heapifyDown(0);}return max;}// 自底向上调整堆heapifyUp() {let i = this.heap.length - 1;while (i > 0) {const parent = Math.floor((i - 1) / 2);if (this.heap[parent] < this.heap[i]) {[this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];i = parent;} else {break;}}}// 自顶向下调整堆heapifyDown(i) {const n = this.heap.length;let largest = i;const left = 2 * i + 1;const right = 2 * i + 2;if (left < n && this.heap[left] > this.heap[largest]) {largest = left;}if (right < n && this.heap[right] > this.heap[largest]) {largest = right;}if (largest !== i) {[this.heap[i], this.heap[largest]] = [this.heap[largest], this.heap[i]];this.heapifyDown(largest);}}// 判断优先队列是否为空isEmpty() {return this.heap.length === 0;}
}// 示例const pq = new PriorityQueue();
pq.insert(10);
pq.insert(5);
pq.insert(20);
console.log(pq.extractMax()); // 输出结果为 20
console.log(pq.extractMax()); // 输出结果为 10
console.log(pq.extractMax()); // 输出结果为 5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3030046.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Python修改exe之类的游戏文件中的数值

文章目录 场景查找修改 补充字节to_bytes 场景 某些游戏数值&#xff08;攻击力、射程、速度…&#xff09;被写在exe之类的文件里 要先查找游戏数值&#xff0c;然后修改 查找 首先&#xff0c;要查找数值&#xff0c;大数重复较少&#xff0c;建议从大数找起 F 游戏原件…

【系统架构师】-案例篇(五)企业应用系统集成与ESB

在航空业中&#xff0c;Ramp Coordination是指飞机从降落到起飞过程中所需要进行的各种业务活动的协调过程。通常每个航班都有一位员工负责Ramp Coordination&#xff0c;称之为RampCoordinator。由Ramp Coordinator协调的业务活动包括检查机位环境、卸货和装货等。 由于航班类…

企业如何做好数据安全治理?

在数字化时代&#xff0c;数据成为企业运营的核心资产&#xff0c;数据安全治理成为企业管理的重要组成部分。良好的数据安全治理不仅能保护企业信息不受侵犯&#xff0c;还能有效提升企业的运营效率和市场竞争力。下面是企业如何做好数据安全治理的几个关键步骤&#xff1a; 1…

【智能算法应用】基于麻雀搜索算法-支持向量回归预测(SSA-SVR)

目录 1.算法原理2.数学模型3.结果展示4.调试记录5.参考文献6.代码获取 1.算法原理 【智能算法】麻雀搜索算法&#xff08;SSA&#xff09;原理及实现 2.数学模型 支持向量机(SVM)是针对二分类问题&#xff0c;支持向量回归(SVR)基于SVM应用与回归问题。SVR回归与SVM分类的区…

【栈】Leetcode 验证栈序列

题目讲解 946. 验证栈序列 算法讲解 在这里就只需要模拟一下这个栈的出栈顺序即可&#xff1a;使用一个stack&#xff0c;每次让pushed里面的元素入栈&#xff0c;如果当前栈顶的元素等于poped容器中的当前元素&#xff0c;因此就需要让栈顶元素出栈&#xff0c;poped的遍历…

ArcGIS10.2能用了10.2.2不行了(解决)

前两天我们的推文介绍了 ArcGIS10.2系列许可到期解决方案-CSDN博客文章浏览阅读2次。本文手机码字&#xff0c;不排版了。 昨晚&#xff08;2021\12\17&#xff09;12点后&#xff0c;收到很多学员反馈 ArcGIS10.2系列软件突然崩溃。更有的&#xff0c;今天全单位崩溃。​提示许…

西米支付:数字藏品元宇宙的介绍与骗局套路解析

一、什么是元宇宙&#xff1f; 元宇宙是一个集体虚拟共享空间&#xff0c;由虚拟增强的物理现实和物理持久的虚拟空间融合而创造&#xff0c;包括所有虚拟世界、增强现实和互联网的总和。简单地说&#xff0c;元宇宙是Web3.0时期的数字世界。 这类新兴概念被非法分子包装后&am…

ssrf(第二弹)

四&#xff0c;post请求 1.打开环境&#xff0c;提示说发一个HTTP POST请求&#xff0c;ssrf是用php的curl实现的.并且会跟踪302跳转。 2.用dirsearch扫一下常见的端口&#xff0c;看到有三个可以访问的页面 3.构造伪协议&#xff0c;因为要通过172.0.0.1访问&#xff0c;我们…

TikTok shop多账户需要防关联吗?

TikTok是一个非常垂直的平台&#xff0c;每个账号的内容都应该尽可能的垂直&#xff0c;这样平台才能引流更多的流量。但是&#xff0c;TikTokShop只有一两个账号&#xff0c;流量往往难以保证&#xff0c;所以很多商家选择了TikTok的多账号运营模式。 众所周知&#xff0c;多店…

数字音频的采样和量化

一.PCM&#xff08;Pulse-Code Modulation 脉冲编码调制&#xff09; PCM是一个无损无压缩的&#xff08;相较于有损压缩&#xff0c;如果相对于模拟信号是有损的&#xff09;数字化编码方式&#xff08;PCM不单单应用于音频领域&#xff0c;本文只介绍在音频领域中的应用&…

GAMMA Lab——知识图谱和LLM大模型

图机器学习的发展与分类 图基础模型 LLM基础模型 GNN LLM 前沿工作

【智能算法】正切搜索算法(TSA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2022年&#xff0c;A Layeb受到正切函数启发&#xff0c;提出了正切搜索算法&#xff08;Tangent Search Algorithm, TSA&#xff09;。 2.算法原理 2.1算法思想 TSAT基于正切函数的数学…

(Mac)RocketMQ的本地安装测试(详细图示)

目录 部署服务 namesrv / broker下载解压缩运行 namesrvnohup ./bin/mqnamesrv & 启动命令详解运行 broker 测试收发消息运行自带的生产者测试类运行自带的消费者测试类 部署 Dashboard 可视化下载打包运行访问 部署服务 namesrv / broker 下载解压缩 官网下载 https://r…

uniapp、web网页跨站数据交互及通讯

来来来&#xff0c;说说你的创作灵感&#xff01;这就跟吃饭睡觉一样&#xff0c;饿了就找吃的&#xff0c;渴了就倒水张口灌。 最近一个多月实在是忙的没再更新日志&#xff0c;好多粉丝私信说之前的创作于他们而言非常有用&#xff01;受益菲浅&#xff0c;这里非常感谢粉丝…

无人直播新模式——视频挂机自动播,一小时收益上千元,思路分享!

无人直播新模式——视频挂机自动播&#xff0c;一小时收益上千元&#xff0c;思路分享&#xff01; 无人直播新模式——视频挂机自动直播是一种创新的直播方式&#xff0c;能够实现自动化的收益。下面将分享一些思路、玩法和流程&#xff0c;帮助您了解这个模式并进行实施。 1、…

内容安全(DPI和DFI解析)

内容安全前言&#xff1a; 防火墙的本质其实就是包过滤&#xff0c;我们通常所说的安全设备&#xff08;如&#xff1a;IPS、IDS、AV、WAF&#xff09;的检测重心是应用层。下一代防火墙基于传统防火墙的拓展能力&#xff0c;就是可以将以上的安全设备模块集成在一起&#xff0…

uniapp的app端软件更新弹框

1&#xff1a;使用html PLUS实现&#xff1a;地址HTML5 API Reference (html5plus.org)&#xff0c;效果图 2&#xff1a;在app.vue的onLaunch生命周期中&#xff0c;代码如下&#xff1a; onLaunch: function() {let a 0let view new plus.nativeObj.View(maskView, {backg…

IO流-其他流:数据流,序列化流

import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream;public class DataOutputStream1 {public static void main(String[] args) {//创建一个数据输出流包装一个低级的字节输出流try (DataOutputStream dosnew DataOutp…

Elasticsearch:RBAC 和 RAG - 最好的朋友

作者&#xff1a;来自 Elastic Jeff Vestal 检索增强生成 (RAG) 通过提供额外的上下文或信息来增强大型语言模型 (LLM) 的知识&#xff0c;从而提高响应质量。 尽管 LLMs 拥有令人印象深刻的能力&#xff0c;但也有其局限性&#xff0c;例如无法在培训后保留新信息以及对不熟悉…

软考网络工程师 第六章 第三部分 第三节 流量控制和拥塞控制

TCP流量控制 流量控制&#xff1a;为了防止发送方防止发送速度过快&#xff0c;导致接受方处理不过来&#xff0c;造成丢包重传&#xff0c;浪费网络资源 TCP流量控制机制&#xff1a;可变大小的滑动窗口 TCP滑动窗口机制 TCP拥塞控制 例题&#xff1a; TCP采用拥塞窗口&am…