一文深度了解堆

news2024/12/23 20:37:12

什么是堆?

堆(Heap)是一种基于数组的树形数据结构,其中每个节点都有一个值,且每个节点的值都大于等于(或小于等于)其子节点的值。堆分为大顶堆(Max Heap)和小顶堆(Min Heap)两种。 在本教程中,我们将使用JavaScript编写大顶堆小顶堆的相关代码。

堆的类型 

大顶堆

大顶堆的特点是每个节点的值都大于等于其子节点的值。因此,大顶堆的根节点的值一定是最大值。

定义一个数组来存储大顶堆

this.heap = []; // 使用数组来表示大顶堆

获取父节点的索引

  // 获取父节点的索引
  getParentIndex(index) {
    return index >> 1; // 右移1位 等价于 Math.floor((index - 1) / 2);
  }

 获取左右子节点的索引

  // 获取左子节点的索引
  getLeftChildIndex(index) {
    return 2 * index + 1;
  }

  // 获取右子节点的索引
  getRightChildIndex(index) {
    return 2 * index + 2;
  }

交换两个元素的位置swap

  // 交换两个元素的位置
  swap(i, j) {
    [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
  }

向上调整shiftUp

// 向上调整,使得以index为根的子树满足大顶堆特性
 shiftUp(index) {
    if (index === 0) return; // 已经到达根节点,无需再调整

    const parentIndex = this.getParentIndex(index);
    if (this.heap[parentIndex] < this.heap[index]) {
      this.swap(parentIndex, index); // 如果父节点的值小于当前节点,交换它们的位置
      this.shiftUp(parentIndex); // 递归向上调整
    }
  }

 向下调整shiftDown

  // 向下调整,使得以index为根的子树满足大顶堆特性
  shiftDown(index) {
    const leftChildIndex = this.getLeftChildIndex(index);
    const rightChildIndex = this.getRightChildIndex(index);
    let largestIndex = index; // 先假设当前节点是最大值

    // 找出当前节点、左子节点和右子节点中的最大值的索引
    if (leftChildIndex < this.heap.length && this.heap[leftChildIndex] > this.heap[largestIndex]) {
      largestIndex = leftChildIndex;
    }
    if (rightChildIndex < this.heap.length && this.heap[rightChildIndex] > this.heap[largestIndex]) {
      largestIndex = rightChildIndex;
    }

    if (largestIndex !== index) {
      this.swap(largestIndex, index); // 如果最大值不是当前节点,交换它们的位置
      this.shiftDown(largestIndex); // 递归向下调整
    }
  }

 插入元素

insert函数用于插入元素,我们将元素插入到数组末尾,然后向上调整新元素的位置

// 插入元素
  insert(value) {
    this.heap.push(value); // 将新元素放到数组末尾
    this.shiftUp(this.heap.length - 1); // 向上调整新元素的位置
  }

移除并返回堆顶元素

extractMax函数用于删除元素,我们首先将根节点(即最大值)移动到数组的末尾,然后将其与子节点比较,如果小于子节点的值,则与较大的子节点交换位置,一直重复此操作,直到不再小于子节点或者到达叶子节点位置。

 // 移除并返回堆顶元素
  extractMax() {
    if (this.heap.length === 0) return null;

    const maxValue = this.heap[0]; // 保存堆顶元素的值
    this.swap(0, this.heap.length - 1); // 将堆顶元素与最后一个元素交换位置
    this.heap.pop(); // 移除最后一个元素
    this.shiftDown(0); // 向下调整新的堆顶元素的位置
    return maxValue;
  }

 

小顶堆

小顶堆的特点是每个节点的值都小于等于其子节点的值。因此,小顶堆的根节点的值一定是最小值。

在代码实现上,大顶堆和小顶堆的区别主要体现在两个方法:shiftUp(向上调整)和shiftDown(向下调整)。

参考大顶堆的代码,将其中的比较符号(><)互换即可实现小顶堆:

向上调整


  // 向上调整,使得以index为根的子树满足小顶堆特性
  shiftUp(index) {
    if (index === 0) return; // 已经到达根节点,无需再调整

    const parentIndex = this.getParentIndex(index);
    if (this.heap[parentIndex] > this.heap[index]) {
      this.swap(parentIndex, index); // 如果父节点的值大于当前节点,交换它们的位置
      this.shiftUp(parentIndex); // 递归向上调整
    }
  }

向下调整

 // 向下调整,使得以index为根的子树满足小顶堆特性
  shiftDown(index) {
    const leftChildIndex = this.getLeftChildIndex(index);
    const rightChildIndex = this.getRightChildIndex(index);
    let smallestIndex = index; // 先假设当前节点是最小值

    // 找出当前节点、左子节点和右子节点中的最小值的索引
    if (leftChildIndex < this.heap.length && this.heap[leftChildIndex] < this.heap[smallestIndex]) {
      smallestIndex = leftChildIndex;
    }
    if (rightChildIndex < this.heap.length && this.heap[rightChildIndex] < this.heap[smallestIndex]) {
      smallestIndex = rightChildIndex;
    }

    if (smallestIndex !== index) {
      this.swap(smallestIndex, index); // 如果最小值不是当前节点,交换它们的位置
      this.shiftDown(smallestIndex); // 递归向下调整
    }
  }

堆的特点

  • 堆是一个完全二叉树,即除了最后一层外,每一层都是满二叉树。这使得堆的插入和删除操作可以在O(log n)的时间复杂度内完成。

  • 堆可以看作是一个优先队列,每次取出的元素都是当前堆中优先级最高的元素。

  • 堆的操作通常涉及到堆化(heapify)和上浮(percolate)两个过程,这两个过程可以帮助调整堆的结构,使其满足堆的性质。

堆的操作

  • 建立堆:首先将给定的元素按照从小到大的顺序排列,然后从最后一个非叶子节点开始,依次向上调整每个节点及其子节点的值,使其满足堆的性质。这个过程称为堆化。

  • 插入元素:在堆的任意位置插入一个新元素,首先将其与其父节点进行比较,如果新元素大于父节点,则交换它们的位置;然后继续向上调整父节点及其子节点的值,使其满足堆的性质。这个过程称为上浮。

  • 删除元素:从堆中删除指定位置的元素,首先将其与其父节点进行比较,如果新元素小于父节点,则交换它们的位置;然后继续向上调整父节点及其子节点的值,使其满足堆的性质。这个过程称为下沉。

  • 获取最大值:在堆中获取最大值的方法是从根节点开始,依次向下查找,直到找到一个没有右子节点的节点,即为最大值。

  • 获取最小值在堆中获取最小值的方法是从根节点开始,依次向下查找,直到找到一个没有左子节点的节点,即为最小值。注意,如果堆为空,则无法获取最大值和最小值。

堆的应用实例

堆排序算法

堆排序算法利用堆的性质对元素集合进行排序,主要分为下面两个实现步骤:

  • 构建堆:首先,将给定的无序数组构造成一个最小堆(或最大堆);

  • 排序:然后,不断的导出堆顶元素并记录,直到堆为空。

优先队列 

优先队列是一种特殊的数据结构,它允许元素按照其优先级进行插入和删除,并确保具有最高优先级的元素位于堆顶。优先队列通常支持插入和删除操作(对应堆的插入和删除操作):

  • 插入操作 push:元素可以被插入到优先队列中,插入操作需要根据元素的优先级来确定其在队列中的位置。

  • 删除操作 pop:删除操作通常是移除优先级最高的元素并返回。

下面我们结合一道力扣上的题目,使用堆来实现一个优先队列以解决问题:

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

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

相关文章

回答网友一个C#对话框位置的问题

起因 ‭ 2024-08-28 19:40:20 colorDialog 打开出现的 位置控制不了 鸽子 2024-08-28 20:06:06 你是可以控制的 ‭ 0:00:47 试了下没用&#xff0c;可能是系统 问题吧 代码 位置的设置 SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0, 1); 核心代码 protected override IntPt…

django学习入门系列之第十点《django的模板语法》

文章目录 获取请求与响应request获取请求方式在url中传递值在结构体中传递值返回一个值读取HTML中的内容 重定向&#xff08;跳转网页&#xff09;往期回顾 获取请求与响应 request request是一个对象&#xff0c;封装了用户通过浏览器发送过来的所有数据获取请求方式 获取请…

Ai产品经理的探索:技能、机遇与未来展望

Ai时代的产品经理 随着人工智能&#xff08;AI&#xff09;的飞速发展&#xff0c;AI已经从一个前沿技术概念逐步演变为驱动各行业创新的核心力量。从智能助手到自动驾驶&#xff0c;从个性化推荐系统到图像识别&#xff0c;AI正在以不可思议的速度改变着我们的生活方式和工作…

python解释器[源代码层面]

1 PyDictObject 在c中STL中的map是基于 RB-tree平衡二元树实现&#xff0c;搜索的时间复杂度为O(log2n) Python中PyDictObject是基于散列表(散列函数)实现&#xff0c;搜索时间最优为O(1) 1.1 散列列表 问题&#xff1a;散列冲突&#xff1a;多个元素计算得到相同的哈希值 …

华为IS-IS实验及配置

AR1配置 #进入ISIS进程 isis 1 #配置设备类型为Level-1is-level level-1 #定义区域和System-ID等信息network-entity 49.0001.0010.0000.0001.00 #ISIS邻居命名is-name AR1 #接口配置IP和启用ISIS interface GigabitEthernet0/0/0ip address 10.1.12.1 255.255.255.0 isis ena…

【C++】C++ STL 探索:String的使用与理解

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶 这篇文章将带大家深入探讨C STL中的string使用与理解。在接下来的几篇文章中&#xff0c;我们将介绍…

WT2605C蓝牙语音芯片:引领糖尿病管理智能化,优化血糖仪音频与蓝牙传输方案

开发背景 全球糖尿病成人患者数量截至2021年约为5.37亿&#xff0c;并预计到2045年将增长至7.83亿。患病率不仅随年龄增长&#xff0c;还展现出明显的地域差异&#xff0c;例如巴基斯坦的患病率最高。此外&#xff0c;老年人群和某些特定地区的居民面临更高的糖尿病风险。 语音…

Leetcode 22. 括号生成 回溯 C++实现

Leetcode 22.括号生成 问题&#xff1a;数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且有效的括号组合。 算法&#xff1a; 创建返回数组 ans &#xff0c;和临时变量 path 。 当左括号数量 open 小于应填括号数 n 时&#…

【Python机器学习】NLP词中的数学——主题建模

目录 齐普夫定律 相关度排序 工具 其他工具 Okapi BM25 在文档向量中&#xff0c;词计数是有用的&#xff0c;但是纯词计数&#xff0c;即使按照文档长度进行归一化处理&#xff0c;也不能告诉我们太多该词在当前文档相对于语料库中其他文档的重要度信息。如果能弄清楚这些…

carla unreal engine源码:如何创建radar可视化探测锥

文章目录 前言一、C实现方法1、DrawDebugCone函数2、carla工程修改3、make launch4、探测锥验证 二、蓝图实现方法1、创建并打开蓝图2、打开蓝图事件图表3、绘制蓝图事件4、编译再运行 前言 1、在自动驾驶仿真调试以及测试过程中&#xff0c;我们经常会用到雷达的探测锥&#…

SkyWalking部署(监控系统)

简介 SkyWalking 是一个开源的应用性能监控 (APM) 和可观测性平台&#xff0c;旨在帮助开发者、运维人员和架构师监控、诊断和优化微服务架构中的应用。SkyWalking 提供了一套完整的工具链&#xff0c;用于收集、分析和可视化应用的性能指标、追踪和日志数据。 SkyWalking 的…

wpf prism 《2》、导航

》》》主程序 using Prism.Commands; using Prism.Mvvm; using Prism.Navigation; using Prism.Navigation.Regions; using System;namespace BlankApp2.ViewModels {public class MainViewModel : BindableBase{private string _title "Prism Application";public…

数据结构《排序》

在之前数据结构之算法复杂度章节中我们学习了复杂度相关的概念&#xff0c;这就使得懂得如何来区分算法的好坏&#xff0c;在之前C语言专题中在指针的学习时我们了解了冒泡排序&#xff0c;之后再数据结构的二叉树章节中我们又学习了堆排序&#xff0c;其实排序不止这两种&…

搜剧平台源码 可一键转存他人链接

简介 1、一键转存他人链接&#xff1a;就是将别人的分享链接转为你自己的 2、转存心悦搜剧资源&#xff1a;就是将心悦搜剧平台上的所有资源都转成你自己的 3、每日自动更新&#xff1a;自动转存每天的资源并入库 前端uin-app&#xff0c;后端PHP&#xff0c;兼容微信小程序…

基于vue框架的博物馆预约网站的设计与实现8k352(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,类别,博物馆,预约信息,馆藏精品 开题报告内容 基于Vue框架的博物馆预约网站的设计与实现开题报告 一、开题报告名称 基于Vue框架的博物馆预约网站的设计与实现 二、研究背景与意义 随着信息技术的飞速发展和人们生活水平的日益…

QT5.14.2编译有界面的DLL供C#Winform程序调用步骤

目标&#xff1a;公司要设计一套软键盘程序给到WinForm程序调用、因此需要封装QT的软键盘程序给到C#调用&#xff0c;跟C#调用MFC的DLL代码差不多&#xff0c;感觉就是封装了一下QT的代码成为MFC格式的。 步骤&#xff1a;1、新建QT对应的库项目、编译器使用MSVC2017 64位、编…

Apache RocketMQ 中文社区全新升级丨阿里云云原生 7 月产品月报

云原生月度动态 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》&#xff0c;从趋势热点、产品新功能、服务客户、开源与开发者动态等方面&#xff0c;为企业提供数字化的路径与指南。 趋势热点 &#x1f947; 通义灵码入选 2024 世界人工智能大会最高荣誉「镇…

Beyond Compare忽略特定格式文本,忽略匹配正则表达式

一 概述 文本对比时忽略某些文本。比如有些生成的文件需要做差异对比&#xff0c;除了内容有差异外&#xff0c;自动生成的ID也不同&#xff0c;想忽略这些ID。特别是文件内容比较多的时候。 如上图&#xff0c;其中UUID“*”的部分我想忽略。 二 方法 方法1 通过Beyond Co…

开放大世界的碰撞与物理

众所周知&#xff0c;物理开销一直是 CPU 的一个大头&#xff0c;而且还很容易出问题。对于开放世界&#xff0c;该如何进行物理运算&#xff0c;以及采用什么方案计算碰撞。 本文针对这个问题做了一些细微的研究&#xff0c;算是对 Unity 下的解决方案有了一个大致的方向。 1、…

《“草莓”引领风潮:全能AI与专业型AI的未来市场较量》

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…