【数据结构与算法】之“堆”介绍

目录

堆的基本存储

一、概念及其介绍

二、适用说明

三、结构图示

堆的 shift up

堆的 shift down

基础堆排序

一、概念及其介绍

二、适用说明

三、过程图示

优化堆排序

索引堆及其优化

一、概念及其介绍

二、适用说明

三、结构图示


堆的基本存储

一、概念及其介绍

堆(Heap)是计算机科学中一类特殊的数据结构的统称。

堆通常是一个可以被看做一棵完全二叉树的数组对象。

堆满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值。
  • 堆总是一棵完全二叉树。

二、适用说明

堆是利用完全二叉树的结构来维护一组数据,然后进行相关操作,一般的操作进行一次的时间复杂度在 O(1)~O(logn) 之间,堆通常用于动态分配和释放程序所使用的对象。

若为优先队列的使用场景,普通数组或者顺序数组,最差情况为 O(n^2),堆这种数据结构也可以提高入队和出队的效率。

入队出队
普通数组O(1)O(n)
顺序数组O(n)O(1)
O(logn)O(log)

三、结构图示

二叉堆是一颗完全二叉树,且堆中某个节点的值总是不大于其父节点的值,该完全二叉树的深度为 k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k 层所有的结点都连续集中在最左边。

其中堆的根节点最大称为最大堆,如下图所示:

我们可以使用数组存储二叉堆,右边的标号是数组的索引。

假设当前元素的索引位置为 i,可以得到规律:

parent(i) = i/2(取整)
left child(i) = 2*i
right child(i) = 2*i +1

堆的 shift up

本小节介绍如何向一个最大堆中添加元素,称为 shift up

假设我们对下面的最大堆新加入一个元素52,放在数组的最后一位,52大于父节点16,此时不满足堆的定义,需要进行调整。

首先交换索引为 5 和 11 数组中数值的位置,也就是 52 和 16 交换位置。

此时 52 依然比父节点索引为 2 的数值 41 大,我们还需要进一步挪位置。

这时比较 52 和 62 的大小,52 已经比父节点小了,不需要再上升了,满足最大堆的定义。我们称这个过程为最大堆的 shift up。

堆的 shift down

本小节将介绍如何从一个最大堆中取出一个元素,称为 shift down,只能取出最大优先级的元素,也就是根节点,把原来的 62 取出后,下面介绍如何填补这个最大堆。

第一步,我们将数组最后一位数组放到根节点,此时不满足最大堆的定义。

调整的过程是将这个根节点 16 一步一步向下挪,16 比子节点都小,先比较子节点 52 和 30 哪个大,和大的交换位置。

继续比较 16 的子节点 28 和 41,41 大,所以 16 和 41 交换位置。

继续 16 和孩子节点 15 进行比较,16 大,所以现在不需要进行交换,最后我们的 shift down 操作完成,维持了一个最大堆的性质。

基础堆排序

一、概念及其介绍

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。

堆是一个近似 完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

二、适用说明

我们之前构造堆的过程是一个个数据调用 insert 方法使用 shift up 逐个插入到堆中,这个算法的时候时间复杂度是 O(nlogn),本小节介绍的一种构造堆排序的过程,称为 Heapify,算法时间复杂度为 O(n)

三、过程图示

完全二叉树有个重要性质,对于第一个非叶子节点的索引是 n/2 取整数得到的索引值,其中 n 是元素个数(前提是数组索引从 1 开始计算)。

索引 5 位置是第一个非叶子节点,我们从它开始逐一向前分别把每个元素作为根节点进行 shift down 操作满足最大堆的性质。

索引 5 位置进行 shift down 操作后,22 和 62 交换位置。

对索引 4 元素进行 shift down 操作

对索引 3 元素进行 shift down 操作

对索引 2 元素进行 shift down 操作

最后对根节点进行 shift down 操作,整个堆排序过程就完成了。

优化堆排序

上一节的堆排序,我们开辟了额外的空间进行构造堆和对堆进行排序。这一小节,我们进行优化,使用原地堆排序。

对于一个最大堆,首先将开始位置数据和数组末尾数值进行交换,那么数组末尾就是最大元素,然后再对W元素进行 shift down 操作,重新生成最大堆,然后将新生成的最大数和整个数组倒数第二位置进行交换,此时倒数第二位置就是倒数第二大数据,这个过程以此类推。

整个过程可以用如下图表示:

 

索引堆及其优化

一、概念及其介绍

索引堆是对堆这个数据结构的优化。

索引堆使用了一个新的 int 类型的数组,用于存放索引信息。

相较于堆,优点如下:

  • 优化了交换元素的消耗。
  • 加入的数据位置固定,方便寻找。

二、适用说明

如果堆中存储的元素较大,那么进行交换就要消耗大量的时间,这个时候可以用索引堆的数据结构进行替代,堆中存储的是数组的索引,我们相应操作的是索引。

三、结构图示

我们需要对之前堆的代码实现进行改造,换成直接操作索引的思维。首先构造函数添加索引数组属性 indexes。

protected T[] data;      // 最大索引堆中的数据
protected int[] indexes;    // 最大索引堆中的索引
protected int count;
protected int capacity;

相应构造函数调整为,添加初始化索引数组。

...
public IndexMaxHeap(int capacity){data = (T[])new Comparable[capacity+1];indexes = new int[capacity+1];count = 0;this.capacity = capacity;
}
...

调整插入操作,indexes 数组中添加的元素是真实 data 数组的索引 indexes[count+1] = i。

...
// 向最大索引堆中插入一个新的元素, 新元素的索引为i, 元素为item
// 传入的i对用户而言,是从0索引的
public void insert(int i, Item item){assert count + 1 <= capacity;assert i + 1 >= 1 && i + 1 <= capacity;i += 1;data[i] = item;indexes[count+1] = i;count ++;shiftUp(count);
}
...

调整 shift up 操作:比较的是 data 数组中父节点数据的大小,所以需要表示为 data[index[k/2]] < data[indexs[k]],交换 index 数组的索引,对 data 数组不产生任何变动,shift down 同理。

...
//k是堆的索引
// 索引堆中, 数据之间的比较根据data的大小进行比较, 但实际操作的是索引
private void shiftUp(int k){while( k > 1 && data[indexes[k/2]].compareTo(data[indexes[k]]) < 0 ){swapIndexes(k, k/2);k /= 2;}
}
...

从索引堆中取出元素,对大元素为根元素 data[index[1]] 中的数据,然后再交换索引位置进行 shift down 操作。

...
public T extractMax(){assert count > 0;T ret = data[indexes[1]];swapIndexes( 1 , count );count --;shiftDown(1);return ret;
}
...

也可以直接取出最大值的 data 数组索引值

...
// 从最大索引堆中取出堆顶元素的索引
public int extractMaxIndex(){assert count > 0;int ret = indexes[1] - 1;swapIndexes( 1 , count );count --;shiftDown(1);return ret;
}
...

修改索引位置数据

...
// 将最大索引堆中索引为i的元素修改为newItem
public void change( int i , Item newItem ){i += 1;data[i] = newItem;// 找到indexes[j] = i, j表示data[i]在堆中的位置// 之后shiftUp(j), 再shiftDown(j)for( int j = 1 ; j <= count ; j ++ )if( indexes[j] == i ){shiftUp(j);shiftDown(j);return;}
}
...

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算顺序表中值在100到500之间的元素个数

要求顺序表中值在100到500之间的元素的个数&#xff0c;你可以使用C语言编写一个循环来遍历顺序表中的元素&#xff0c;并在循环中检查每个元素是否在指定的范围内。 #include <stdio.h>#define MAX_SIZE 100 // 假设顺序表的最大容量为100int main() {int arr[MAX_SIZE]…

STM32 Cube项目实战开发过程中--调用Freemodbus通信出现异常问题原因分析--ADC DMA初始化顺序导致串口数据异常问题解决办法

文章目录 1.ADC与DMA初始化顺序导致使用Freemodbus串口通信异常&#xff1a;2.通信异常时串口初始化的顺序为&#xff1a;3.重新调整初始化位置后&#xff0c;通信问题解决&#xff1a;5.重新调整初始化位置后&#xff0c;通信正常&#xff1a;总结&#xff1a;Cube开发库系统默…

【Unity3D赛车游戏制作】设置面板搭建——UGUI复合控件Toggle

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

uniapp快速入门系列(3)- CSS技巧与布局

章节三&#xff1a;CSS技巧与布局 1. uniapp中的样式编写2. 常见布局技巧与实例解析2.1 水平居中布局2.2 垂直居中布局2.3 等高布局2.4 响应式布局 3. CSS动画与过渡效果 在uniapp中&#xff0c;我们使用CSS来设置页面的样式和布局。本章将介绍一些在uniapp中常用的CSS技巧和布…

6个视频素材库,免费、高清、无水印,你值得拥有~

现在做自媒体的朋友真的越来越多了&#xff0c;对一些视频素材的要求也越来越高&#xff0c;除了自己拍摄之外&#xff0c;还可以在网上找各种无版权视频素材&#xff0c;但国内高质量视频素材大多数不免费&#xff0c;那免费的视频素材要去哪里找呢&#xff1f; 今天就给大家…

SQL Server 简介与 Docker Compose 部署

今天我翻阅了在之前公司工作时的笔记&#xff0c;发现了有关数据库的一些记录。当时&#xff0c;我们的项目开始使用 Oracle 数据库&#xff0c;但后来由于一些项目需求的变更&#xff0c;我们切换到了 SQL Server 。值得一提的是&#xff0c;公司当时也开始采用 Docker 技术&a…

普通物理 A2 期末复习

普通物理 A2 期末复习 本文首发于 2023-06-20 在 https://chenhaotian.top/study/general-physics-a2-final-review/ 总结 第十章 机械振动和电磁振荡 10-1 谐振动 弹簧振子的谐振动 位移 速度 加速度 特征量 旋转矢量法 单摆 能量 题&#xff1a;振动方程 题&#xff1a;振…

Astronomaly:利用 CNN 和主动学习识别 400 万张星系图像中的异常

星系中的异常现象是我们了解宇宙的关键。然而&#xff0c;随着天文观测技术的发展&#xff0c;天文数据正以指数级别增长&#xff0c;超出了天文工作者的分析能力。 尽管志愿者可以在线上参与对天文数据的处理&#xff0c;但他们只能进行一些简单的分类&#xff0c;还可能会遗漏…

java日志框架详解-Log4j2

一、概述 Apache Log4j 2 &#xff08;Log4j – Apache Log4j 2&#xff09;是对Log4j的升级&#xff0c;它比其前身Log4j 1.x提供了重大改进&#xff0c;并参考了Logback中优秀的设计&#xff0c;同时修复了Logback架构中的一些问题。被誉为是目前最优秀的Java日志框架&#x…

[UE虚幻引擎] DTCopyFile 插件说明 – 使用蓝图拷贝复制文件 (Windows)

本插件可以在虚幻引擎中使用蓝图对系统的其他文件进行拷贝复制操作。 1. 节点说明 Async Copy File ​ 异步复制文件 Param Source File : 要复制的源文件的完整路径。Param Target File : 要复制的目标文件的完整路径。Param Force Copy : 如果为true&#xff0c;则如果目标…

项目管理必备的22个公式

大家好&#xff0c;我是老原。 趁着国庆时间比较空闲&#xff0c;给你们整理了一些项目管理必备的计算公式&#xff0c;一共22个。 每一个公式都给你们标注了适用情况和使用方法&#xff0c;为了方便你们理解&#xff0c;也加了一些例子&#xff0c;保准你看了就会。 觉得不…

FutureTask和CompletableFuture的模拟使用

模拟了查询耗时操作&#xff0c;并使用FutureTask和CompletableFuture分别获取计算结果&#xff0c;统计执行时长 package org.alllearn.futurtask;import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import lombok.AllArgsConstructor; imp…

基于Java+SpringBoot+Vue线上医院挂号系统的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

2023全网最全requests库和requests模块使用详解(建议收藏)

一、requests简介 #简介&#xff1a;使用requests可以模拟浏览器的请求&#xff0c;比起之前用的urllib&#xff0c;requests模块的api更加便捷&#xff08;本质就是封装了urllib3&#xff09;#注意&#xff1a;requests库发送请求将网页内容下载下来以后&#xff0c;并不会执…

基于SSM线上课程管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Python数据分析实战-实现卡方检验(附源码和实现效果)

实现功能 使用scipy.stats模块中的chi2_contingency函数来执行卡方检验&#xff08;Chi-square test&#xff09;。卡方检验用于检验两个或多个分类变量&#xff08;组别&#xff09;之间是否存在显著关联&#xff08;差异&#xff09;。 例1&#xff1a;从某中学随机抽取两个…

单目标应用:遗传算法(Genetic Algorithm,GA)求解微电网优化MATLAB

一、微网系统运行优化模型 微电网优化模型介绍&#xff1a; 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、遗传算法GA 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;起源于对生物系统所进行的计算机模拟研究&#xff0c;是一种随机全局搜索…

故障注入常用方法有哪些 其重要性是什么

故障注入是一种有效的测试方法&#xff0c;可用于评估系统对异常情况的响应。通过这种测试方法&#xff0c;可以发现系统中的潜在问题&#xff0c;并采取适当措施来改进系统的质量和性能。本文将介绍故障注入常用方法及重要性! 一、故障注入常用方法 1、随机故障注入&#xff1…

实施运维01

一.运维实施工程师所具备的知识 1.运维工程师&#xff0c;实施工程师是啥&#xff1f; 运维工程师负责服务的稳定性&#xff0c;确保服务无间断的为客户提供服务. 实施工程师负责工程的实施工作&#xff0c;负责现场培训&#xff0c;一般都要出差&#xff0c;哪里有项目就去…

【数据结构】什么是算法

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 一.算法的定义 1.算法的概念 2.数据结构与算法的关系 二.算法的特性 输入 输出 有穷性 确定性 可行性 三.算法的设计要求 1.正确性 2.可读性 3.健壮性 4.效…