数据结构-优先级队列(堆)
文章目录
目录
文章目录
前言
一 . 堆
二 . 堆的创建(以大根堆为例)
堆的向下调整(重难点)
堆的创建
堆的删除
向上调整
堆的插入
三 . 优先级队列
总结
前言
大家好,今天给大家讲解一下堆这个数据结构和它的实现 - 优先级队列
一 . 堆
堆(Heap)是一种基于完全二叉树的数据结构,具有以下特点:
-
完全二叉树:堆是一种完全二叉树,即除了最后一层外,其他层的节点都是满的,并且最后一层的节点都靠左排列。
-
堆序性:堆中的每个节点都满足堆序性质,即对于最大堆(Max Heap),父节点的值大于或等于其子节点的值;对于最小堆(Min Heap),父节点的值小于或等于其子节点的值。
堆通常用数组来实现,其中数组的索引表示节点在堆中的位置。对于一个节点在索引i的堆,其左子节点在索引2i,右子节点在索引2i+1,父节点在索引i/2。
堆常常被用来实现优先级队列,因为它能够快速找到最大或最小的元素,并且在插入和删除操作时保持堆序性质。
常见的堆有两种类型:
-
最大堆(大根堆):父节点的值大于或等于其子节点的值。最大堆的根节点是堆中的最大元素。
-
最小堆(小根堆):父节点的值小于或等于其子节点的值。最小堆的根节点是堆中的最小元素。
堆的常见操作包括:
-
插入(Insertion):将一个元素插入到堆中,需要保持堆序性质。
-
删除根节点(Delete Root):删除堆中的根节点,需要调整堆以保持堆序性质。
-
查找最大/最小元素(Find Max/Min):在最大堆中查找最大元素,在最小堆中查找最小元素,时间复杂度为O(1)。
-
堆排序(Heap Sort):利用堆的性质进行排序,时间复杂度为O(nlogn)。
二 . 堆的创建(以大根堆为例)
初始化工作
public class BigHeap {int[] elem; // 用来记录堆中的元素int size;public BigHeap(int capacity) {elem = new int[capacity];}//再初始化的时候默认给一个数组public void initHeap(int[] arr) {for (int i = 0; i < arr.length; i++) {elem[i] = arr[i];size++;}}public boolean isFull() {return elem.length == size;}public void swap(int i,int j){int temp = elem[i];elem[i] = elem[j];elem[j] = temp;}}
堆的向下调整(重难点)
对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成大根堆呢?
父节点的值大于或等于其子节点的值。最大堆的根节点是堆中的最大元素。
根据层序遍历构建出的二叉树显然并不符合我们的要求,这个是时候我们就需要进行向下调整
在最大堆中,向下调整的过程是将当前节点与其子节点中较大的节点进行比较,如果当前节点小于其中较大的子节点,就将它们交换位置。然后,继续向下比较和交换,直到当前节点不再小于其子节点或者已经到达叶子节点。
思考一下,这个时候我们应该从哪个节点进行调整?
我们通常是从最后一个非叶子节点开始向下调整,直到根节点或者到达叶子节点为止。从最后一个非叶子节点开始向下调整的原因是,只有非叶子节点才有子节点,而叶子节点没有子节点,所以没有必要对叶子节点进行向下调整操作。
最后一个非叶子节点的索引可以通过公式计算得到:n/2-1,其中n是堆中元素的数量。
步骤
1. 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子,因为是完全二叉树)
2. 如果parent的左孩子存在,即:child < len, 进行以下操作,直到parent的左孩子不存在
- parent右孩子是否存在,存在找到左右孩子中最大的孩子,让child进行标记
- 将parent与较大的孩子child比较如果:
- parent小大于较大的孩子child,调整结束
- 否则:交换parent与较大的孩子child,交换完成之后,parent中小的元素向下移动,可能导致子树不满足堆的性质,因此需要继续向下调整,即parent = child;child = parent*2+1; 然后继续2(上面的)。
图解
{ 27,15,19,18,28,34,65,49,25,37 }
len: 数组的长度
parent: 表示指向需要调整的节点指针
child: 表示指向孩子节点的指针
最后一个非叶子节点: 根据公式parent = (child-1)/2 在这里child表示最后一个节点的索引
parent = (len - 1 - 1)/2 = 4 我们应该从4索引开始进行向下调整
进行到这里左子树宣告调整完毕,开始进行右子树的调整
调整完毕!
代码实现
private void shiftDown(int parent, int len) {int child = 2 * parent + 1;// 对交换引起的堆结构的改变进行调整(如果改变就调整)while (child < len) {// 找出左右孩子中最大的孩子,用child进行记录if (child + 1 < len && elem[child] < elem[child + 1]) {child++;}// 判断大小关系if (elem[child] > elem[parent]) {swap(child,parent);// parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整parent = child;child = 2 * parent + 1;} else {// 左孩子为空,表示以最开始的parent为根的二叉树已经是大根堆结构break;}}}
堆的创建
public void createHeap() {// 找倒数第一个非叶子节点,从该节点位置开始往前一直到根节点,遇到一个节点,应用向下调整for (int parent = (size - 1 - 1) / 2; parent >= 0; parent--) {shiftDown(parent, size);}}
堆的删除
注意:堆的删除一定删除的是堆顶元素。具体如下:
1. 将堆顶元素对堆中最后一个元素交换
2. 将堆中有效数据个数减少一个
3. 对堆顶元素进行向下调整
public int poll(){int temp = elem[0];swap(0, size);size--;// 调整完之后需要进行先下调整,因为原来的最后一个元素变成了堆顶元素,不用想的肯定不满足大根堆的结构shiftDown(0, size);return temp;}
向上调整
在最大堆中,向上调整的过程是将当前节点与其父节点进行比较,如果当前节点大于其父节点,就将它们交换位置。然后,继续向上比较和交换,直到当前节点不再大于其父节点或者已经到达根节点。
private void shiftUp(int child) {while (child != 0) {int parent = (child - 1) / 2;if (elem[parent] < elem[child]) {swap(child,parent);child = parent;} else {break;}}}
堆的插入
堆的插入总共需要两个步骤:
1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
2. 将最后新插入的节点向上调整,直到满足堆的性质
小根堆中插入10
public void offer(int val) {if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);}elem[size] = val;shiftUp(size);size++;}
总代码
public class BigHeap {int[] elem;int size;public BigHeap(int capacity) {elem = new int[capacity];}public void initHeap(int[] arr) {for (int i = 0; i < arr.length; i++) {elem[i] = arr[i];size++;}}public void createHeap() {for (int parent = (size - 1 - 1) / 2; parent >= 0; parent--) {shiftDown(parent, size);}}public int poll(){int temp = elem[0];swap(0, size);size--;// 调整完之后需要进行先下调整,因为原来的最后一个元素变成了堆顶元素,不用想的肯定不满足大根堆的结构shiftDown(0, size);return temp;}private void shiftDown(int parent, int len) {int child = 2 * parent + 1;// 对交换引起的堆结构的改变进行调整(如果改变就调整)while (child < len) {// 找出左右孩子中最大的孩子,用child进行记录if (child + 1 < len && elem[child] < elem[child + 1]) {child++;}// 判断大小关系if (elem[child] > elem[parent]) {swap(child,parent);// parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整parent = child;child = 2 * parent + 1;} else {// 左孩子为空,表示以最开始的parent为根的二叉树已经是大根堆结构break;}}}public void offer(int val) {if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);}elem[size] = val;shiftUp(size);size++;}private void shiftUp(int child) {while (child != 0) {int parent = (child - 1) / 2;if (elem[parent] < elem[child]) {swap(child,parent);child = parent;} else {break;}}}public boolean isFull() {return elem.length == size;}public void swap(int i,int j){int temp = elem[i];elem[i] = elem[j];elem[j] = temp;}
}
三 . 优先级队列
前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队 列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话;初中那会班主任排座位时可能会让成绩好的同学先挑座位。 在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数 据结构就是优先级队列(Priority Queue)。
优先级队列可以用于很多场景,例如任务调度、进程调度、事件处理等。在任务调度中,可以根据任务的优先级来决定先执行哪些任务;在进程调度中,可以根据进程的优先级来决定先执行哪些进程;在事件处理中,可以根据事件的优先级来决定先处理哪些事件。
在实际应用中,优先级队列可以通过使用堆来实现,因为堆具有良好的时间复杂度和空间复杂度。通过使用堆来实现优先级队列,可以在log₂ n的时间复杂度内插入和删除元素,以及在O(1)的时间复杂度内获取优先级最高的元素。
注意点:
1. 使用时必须导入PriorityQueue所在的包
2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException异常
3. 不能插入null对象,否则会抛出NullPointerException
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
5. 插入和删除元素的时间复杂度为O(log₂ n)
6. PriorityQueue底层使用了堆数据结构
7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素
堆模拟实现优先级队列
class MyPriorityQueue {// 演示作用,不再考虑扩容部分的代码private int[] array = new int[100];private int size = 0;public void offer(int e) {array[size++] = e;shiftUp(size - 1);}public int poll() {int oldValue = array[0];array[0] = array[size--];shiftDown((size-1-1)/2,size);return oldValue;}public int peek() {return array[0];}}
总结
这篇文章给大家重点讲解了堆的模拟实现还有其应用之一 优先级队列,大家好好理解,我们下一篇博客见。
相关文章:
数据结构-优先级队列(堆)
文章目录 目录 文章目录 前言 一 . 堆 二 . 堆的创建(以大根堆为例) 堆的向下调整(重难点) 堆的创建 堆的删除 向上调整 堆的插入 三 . 优先级队列 总结 前言 大家好,今天给大家讲解一下堆这个数据结构和它的实现 - 优先级队列 一 . 堆 堆(Heap࿰…...
C++11新特性(语法糖,新容器)
距离C11版本发布已经过去那么多年了,为什么还称为新特性呢?因为笔者前面探讨的内容,除了auto,范围for这些常用的,基本上是用着C98的内容,虽说C11已经发布很多年,却是目前被使用最广泛的版本。因…...
开机可用内存分析Tip
一、开机内存简介 开机内存指的是开机一段时间稳定后的可用内存。一般项目都会挑选同平台其他优秀竞品内存数据,这个也是衡量性能的一个重要标准。所以要进行开机内存检测,同时优化非法内存进程占用。 二、测试前期核查任务 开机内存测试前要进行测试机…...
【Python基础】4. 基本语句
文章目录 注释(Comment)解释伴随行文本编码问题 输入输出语句(Input & Output)输出语句普通输出格式化输出(3种)format 格式总结 输入语句 基本语句if 语句match 语句(Python3.10 新增&…...
兼顾友好与安全,隐私协议 Unijoin 助推新一轮 Web3 浪潮
区块链本身不仅崇尚去中心化,同时也崇尚公开透明,虽然这正在让 DAO 治理等变得更加公平,但它同时也是一把双刃剑,个人交易者尤其是一些巨鲸交易者的所以链上交易都被公之于众,这似乎并不是他们想要的结果。 所以从加密…...
TCP端口崩溃,msg:socket(): Too many open files
一、现象 linux系统中运行了一个TCP服务器,该服务器监听的TCP端口为10000。但是长时间运行时发现该端口会崩溃,TCP客户端连接该端口会失败: 可以看到进行三次握手时,TCP客户端向该TCP服务器的10000端口发送了SYN报文,…...
基于Laravel 5.6的运动健身类小程序前后端源码
基于Laravel 5.6的运动健身、健康类小程序前后端源码,一套比较基础的运动健康、健身类小程序源码。朋友自己无聊写的,比较基础,有需要的可以拿去修修改改升级开发一下。 使用宝塔安装,比较省事,PHP相关的扩展需要启用…...
NodeMCU ESP8266硬件开发板的熟悉
文章目录 硬件开发环境的熟悉基础介绍什么是 ESP8266 NodeMCU?NodeMCU芯片ESP12-E 模组开发板 ESP8266 版本引脚图Power GND I2CGPIOADCUARTSPIPWMControl 总结 硬件开发环境的熟悉 基础介绍 什么是 ESP8266 NodeMCU? ESP8266是乐鑫开发的一款低成本 …...
计算机毕业设计 基于SSM的在线预约导游系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
Mac 挂载 Alist网盘
挂载服务器的Alist 网盘到 Mac mac,使用的是 CloundMounter 这个软件进行挂载 http://ip:port/dav/ 需要在末尾加上 /dav/ 在一些服务器上,为了提供WebDAV服务,需要在URL地址的末尾添加"/dav/“。这是因为WebDAV协议规定了一些标准的URL路径&#x…...
【多模态融合】TransFusion学习笔记(1)
工作上主要还是以纯lidar的算法开发,部署以及系统架构设计为主。对于多模态融合(这里主要是只指Lidar和Camer的融合)这方面研究甚少。最近借助和朋友们讨论论文的契机接触了一下这方面的知识,起步是晚了一点,但好歹是开了个头。下面就借助TransFusion论文…...
(二)正点原子STM32MP135移植——TF-A移植
目录 一、TF-A概述 二、编译官方代码 2.1 解压源码 2.2 打补丁 2.3 编译准备 (1)修改Makfile.sdk (2)设置环境变量 (3)编译 三、移植 3.1 复制官方文件 3.2 修改电源 3.3 修改TF卡和emmc 3.4 添…...
将二叉搜索树转化为排序的双向链表
链接: LCR 155. 将二叉搜索树转化为排序的双向链表 题解: /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node() {}Node(int _val) {val _val;left NULL;right NULL;}Node(int _val, Node* _left…...
电脑dll丢失应该怎么解决,dll文件丢失怎么恢复方法分享
DLL(Dynamic Link Library,动态链接库)是一种可执行文件,它包含了在程序运行时需要调用的代码和资源。DLL 文件的主要作用是实现代码和资源的共享,这样在多个程序之间就可以避免重复的代码和资源,从而节省系…...
通达信和同花顺能否实现程序化自动交易股票,量化交易如何实现?
以下写给正在寻找自动交易接口的朋友,首先,不是那种设置个简单条件的条件单,或者某些客户端上形同鸡肋的策略交易,那些策略根本称不上策略,还有各种限制,不支持这个不支持那个,可设置的参数也不…...
基于Kylin的数据统计分析平台架构设计与实现
目录 1 前言 2 关键模块 2.1 数据仓库的搭建 2.2 ETL 2.3 Kylin数据分析系统 2.4 数据可视化系统 2.5 报表模块 3 最终成果 4 遇到问题 1 前言 这是在TP-LINK公司云平台部门做的一个项目,总体包括云上数据统计平台的架构设计和组件开发,在此只做…...
Linux CentOS7 vim寄存器
计算机中通常所说的寄存器Register一般指的是CPU中的寄存器,用来暂存CPU处理所需要的指令、数据等。 vim中同样也有寄存器,使用的方式和CPU非常类似。 vim中的寄存器(register)作用和windows中的剪切板类似,不过vim中的寄存器不止一个&…...
摄影后期图像编辑软件Lightroom Classic 2023 mac中文特点介绍
Lightroom Classic 2023 mac是一款图像处理软件,是数字摄影后期制作的重要工具之一,lrc2023 mac适合数字摄影后期制作、摄影师、设计师等专业人士使用。 Lightroom Classic 2023 mac软件特点 高效的图像管理:Lightroom Classic提供了强大的图…...
一种4g扫码付费通电控制器方案
之前开发了一款扫码付款通电控制器 功能:用户扫码付款后设备通电,开始倒计时,倒计时结束后设备断电,资金到账商家的商家助手里面,腾讯会收取千分之6手续费。 产品主要应用场景 本产品主要应用于各类无人值守或者自助…...
桌面自动化工具总结
引言:产品经理提出桌面程序需要自动化的测试,避免繁琐的人肉点击。说干就干。 现有自动化工具是五花八门,我找了两个框架。 这两个框架都是基于微软的UIA 框架,链接地址 https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-providerportal?source=recommen…...
Python入门教程 | Python 常用标准库概览
Python3 标准库概览 Python 标准库非常庞大,所提供的组件涉及范围十分广泛,使用标准库我们可以让您轻松地完成各种任务。 以下是一些 Python3 标准库中的模块: os 模块:os 模块提供了许多与操作系统交互的函数,例如创…...
【JavaScript】读取本地json文件并绘制表格
本文为避免跨域问题,使用了改造过的本地json文件的方法实现读取json数据并绘制表格。 如果发起http请求获取本地 json文件中数据,需要架设本地服务器,本文不做阐述。 概述 1、json在本地,并不需要从服务器下载。 2、采用jquery…...
前端笔试题总结,带答案和解析(一)
1. 执行以下程序,输出结果为() var x 10; var y 20; var z x < y ? x:y; console.log(xx;yy;zz);A x11;y21;z11 B x11;y20;z10 C x11;y21;z10 D x11;y20;z11 初始化x的值为10,y的值为20,x < y返回结果为tru…...
LeetCode 202 快乐数
今天再次做到需要int转化成String,从而方便运算的题目。(当然还可以直接使用int运算也是没问题的) 再次出现了我容易弄混淆的问题,Integer.valueOf和ASCII码转化的差异? 其实之前我以及有记录过该问题,详…...
国庆作业day6
服务器 #include <my_head.h> #define IP "192.168.101.66" #define PORT 6666 int main(int argc, const char *argv[]) {//创建套接字int fd socket(AF_INET, SOCK_STREAM, 0);if(fd < 0){ERR_MSG("socket");return -1;}struct sockaddr_in s…...
李沐深度学习记录4:12.权重衰减/L2正则化
权重衰减从零开始实现 #高维线性回归 %matplotlib inline import torch from torch import nn from d2l import torch as d2l#整个流程是,1.生成标准数据集,包括训练数据和测试数据 # 2.定义线性模型训练 # 模型初始化(函…...
堆--数组中第K大元素
如果对于堆不是太认识,请点击:堆的初步认识-CSDN博客 解题思路: /*** <h3>求数组中第 K 大的元素</h3>* <p>* 解体思路* <ol>* 1.向小顶堆放入前k个元素* 2.剩余元素* 若 < 堆顶元素, 则略过* …...
ipad使用技巧
1、goodnotes中批量导入pdf文件 法一: 直接参考视频: 【目前为止所知iPad上goodnotes批量导入网盘文件最快的方法】 大致步骤:pdf文件传到百度网盘,然后ES软件登录百度网盘,在goodnotes中导入,选择ES&a…...
Windows系统上使用CLion远程开发Linux程序
CLion远程开发Linux程序 情景说明Ubuntu配置CLion配置同步 情景说明 在Windows系统上使用CLion开发Linux程序,安装CLion集成化开发环境时会自动安装cmake、mingw,代码提示功能也比较友好。 但是在socket开发时,包含sys/socket.h头文件时&am…...
github搜索技巧
指定语言 language:java 比如我要找用java写的含有blog的内容 搜索项目名称包含关键词的内容 vue in:name 其他如项目描述跟项目文档,如下 组合使用 vue in:name,description,readme 根据Star 或者fork的数量来查找 总结 springboot vue stars:>1000 p…...
ui中国官网/百度笔记排名优化
《云桌面技术在高校计算机实验室中的应用(原稿).doc》由会员分享,可免费在线阅读全文,更多与《云桌面技术在高校计算机实验室中的应用(原稿)》相关文档资源请在帮帮文库(www.woc88.com)数亿文档库存里搜索。1、单位进行组织教学,并通过台或多台交换机直接…...
海外网站太慢/广州seo实战培训
Mac打字大师好用吗?想要练习打字?那就使用Master Of Typing Mac这款强大的打字练习软件吧!master of typing mac可以提供各种练习,自动设置难度,让你快速提升打字速度,还提供多种测试,让你了解自…...
公明做网站的公司/企业查询网
ctrl 1快速修复 ctrl d 快速删除 ctrl F11快速运行 ctrl m 放大工作区 atl /注释 。。。 转载于:https://www.cnblogs.com/TreeDream/p/5475744.html...
wordpress 分类列表页/网址申请注册
Fiddler工具使用介绍一 Fiddler基础知识 Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改。代理就是在客户端和服务器之间…...
wordpress登录名/网络营销的定义是什么
需要用到IRremote库文件 红外遥控按键16进制编码,使用时添加前缀 0X 红外接收 .源代码 //***************** //红外接收模块测试 //***************** #include <IRremote.h> IRrecv irrecv(6); //创建红外模块对象,并绑定红外接收模块引脚 decode_results …...
做网站要哪些技术/黑马培训机构可靠吗
滑块区间组件 功能需求: 最小值为0,按照给定的最大值,生成区间范围;拖动滑块移动时,显示相应的范围区间,滑块条显示对应的状态;点击时,使最近的滑块移动到鼠标点击的位置。 默认效…...