数据结构(Java):优先级队列(堆)堆的模拟实现

目录

1、优先级队列

1.1 概念

1.2 PriorityQueue底层结构

2、 堆

2.1 堆的概念

 2.2 堆的存储结构

3、优先级队列(堆)的模拟实现

3.1 堆的创建

3.1.1 向下调整算法建完整堆

3.2 堆的插入 

3.2.1 向上调整算法

 3.3 堆的删除

3.4 堆排序


1、优先级队列

1.1 概念

对于队列而言,数据只能从队尾进,队头出,遵循着固定的先进先出原则。

而在某些特殊场景需求下,要求优先级高的元素先出队列,

在这种情况下,数据结构应该提供两个最基本的操作:

  • ①:不仅能添加新对象
  • ②:还能返回最高优先级对象。

这种数据结构就是优先级队列,Java也提供了PriorityQueue集合。 

1.2 PriorityQueue底层结构

PriorityQueue底层是堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整,接下来,让我们来聊一聊堆到底是什么。


2、 堆

2.1 堆的概念

 所有元素按完全二叉树的顺序存储方式存储在一个一维数组中。

堆分为 大根堆与小根堆。

大根堆:每个节点都大于或等于其子节点。

小根堆:每个节点都小于或等于其子节点。


 2.2 堆的存储结构

我们已知堆为一棵完全二叉树,故采用顺序的方式存储在数组中。

而对于我们之前所学的二叉树,为什么没有采用顺序存储而是采用链式存储呢?

因为二叉树并非都为完全二叉树,若采用顺序存储会造成空间浪费:

因为堆采用顺序的方式进行存储,且为完全二叉树,故具有以下性质:

  1. 孩子节点下标为i,则其父亲节点下标为(i - 1)/2
  2. 父亲下标为i,则其左孩子下标为2i+1(2i+1<节点总数的情况下,否则无左孩子)
  3. 父亲下标为i,则其右孩子下标为2i+2(2i+2<节点总数的情况下,否则无右孩子)

3、优先级队列(堆)的模拟实现

注:下文中代码实现的为大根堆

3.1 堆的创建

 向下调整算法

向下调整算法:选出其左右孩子中值较小值元素(建大堆就选较大元素,建小堆就选较小元素,这里以建小堆为例),将这个元素和根节点进行比较,若比根节点还小,就和根节点交换,交换后可能导致子树不满足堆的性质,因此需要继续向下调整。

注意:向下调整算法的使用,必须要求其左右子树必须为大根堆或者小根堆!!!

向下调整算法的时间复杂度为:O(logN),因为最坏情况是从根一路比较到叶子,比较的次数即为完全二叉树的高度次。

3.1.1 向下调整算法建完整堆

我们给出一组数据:{ 27,15,19,18,28,34,65,49,25,37 },要想将这组数据建成堆,我们可以使用向下调整法建堆。

而一组乱序数据其左右子树是不为堆的,那就需要通过向下调整算法从倒数第一个非叶子节点(下标为(数组.length-1-1)/2 )开始建堆,直到将整棵树建成堆。

建堆的时间复杂度为:O(N)!!!,

什么不是O(N*logN)呢?这里给出解释:

向下调整整体建堆代码:

/*** 建堆整体时间复杂度:O(N)*/public void createHeap() {//从倒数第一个飞非叶子节点开始建堆int parent = (this.usedSize - 1 - 1)/2;while (parent >= 0) {//O(N)siftDown(parent,this.usedSize);parent--;}}/***向下调整算法* 时间复杂度:O(logN)* @param parent 向下调整的起始位置,即根节点* @param usedSize 标定调整的结束 若算出的孩子节点坐标>=usedSize时,说明已调整完成*/private void siftDown(int parent, int usedSize) {int child = parent*2+1;//当没有孩子节点时,说明向下调整完成while (child < usedSize) {//当右孩子存在时,选出左右孩子的最大值(建大堆)if (child + 1 < usedSize) {if (elem[child] < elem[child + 1]) {child = child + 1;}}//和根节点进行比较if (elem[child] > elem[parent]) {swap(elem, parent, child);parent = child;child = parent*2+1;}else {//若根节点大,说明已是大堆,break结束break;}}}

3.2 堆的插入 

插入数据总共有两个步骤:

  1. 将新元素插入堆的末尾(插入后不再为堆)
  2. 使用向上调整算法调整为堆 

3.2.1 向上调整算法

(这里以建小堆为例):将元素插入到堆的末尾后,和根节点进行比较,如果比根节点还小就和根节点换,继续向上调整,直至满足堆的性质。如果没有根节点小,说明此时已满足堆的性质,调整完成。

时间复杂度:O(logN)

插入元素代码:

/*** 插入元素* 时间复杂度:O(logN)* @param x:新插入元素的值*/public void offer(int x) {if (isFull()) {grow();}elem[usedSize] = x;siftUp(usedSize);usedSize++;}/*** 向下调整算法* @param childIndex:新插入元素的下标*/public void siftUp(int childIndex) {//找到新节点的父节点的下标int parent = (childIndex - 1)/2;//parent为负数时,说明调整完成(最坏)while (parent >= 0) {if (elem[parent] < elem[childIndex]) {swap(elem,parent,childIndex);childIndex = parent;parent = (childIndex - 1)/2;}else {break;}}}/*** 如果堆底层的数组满了,就扩容*/private void grow() {this.elem = Arrays.copyOf(elem,elem.length*2);}

向上调整算法建堆【拓展】 

故我们也可以一个一个的插入元素(使用向上调整算法)来建堆,但是不推荐,因为时间复杂度比向下调整算法建堆要大,为:O(N*logN)

其实主要原因就是:最后一层的元素是最多的,都要一个个向上调整


 3.3 堆的删除

堆的删除一定删除的是堆顶元素。

故,删除元素的思想很简单,即:

  1.  将堆顶元素和堆中最后一个元素交换
  2.  将堆中有效数据个数(usedSize)减一
  3.  对堆顶元素进行向下调整(只需要调整0下标就可以了)

 堆删除代码:

/*** 删除堆元素*/public void poll() {if (isEmpty()) {//如果堆为空,返回return;}//交换堆顶和最后一个元素swap(elem,0,usedSize-1);//堆元素有效个数-1usedSize--;//只向下调整0下标即可siftDown(0,usedSize);}

3.4 堆排序

若要升序排列,要建大根堆;若要降序排列,就要建小根堆。

以排升序为例:若要排升序,则为大堆,排序过程如下:

  1. 将堆顶元素和堆末元素交换,有效数据个数减一(因为堆顶元素为最大值元素,此时最大值元素已来到数组末尾)
  2. 将0下标处向下调整,重新调整为大堆
  3. 继续将堆顶元素和堆末元素交换,有效数据个数减一(堆顶元素为次大值元素,此时次大值元素已来到数组末尾倒数二个位置处)
  4. 将0下标处向下调整,重新调整为大堆
  5. 重复以上过程,直至只剩一个元素的时候,此时数组已有序且为升序排列

堆排序 排升序代码 :

/*** 堆排序*/public void heapSort() {if (isEmpty()) {return;}int end = usedSize-1;while (end > 0) {swap(elem,0,end);siftDown(0,end);end--;}}

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

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

相关文章

CH552的bootload程序IAP直接对ROM-flash修改数据(未尝试)

手动写bootload程序的可能 1&#xff0c;根据ch552g的使用手册内容查看到 2&#xff0c;在下面的参考文件的IAP文件夹中看到IAP文件 参考 下面程序中并没有跳转到厂家bootload的过程&#xff0c;这是直接通过控制有关的寄存器对FLSH进行直接写入和修改&#xff0c;这样可以认…

如何学习Hadoop:糙快猛的大数据之路(利用GPT 学习)

目录 引言Hadoop是什么&#xff1f;学习Hadoop的"糙快猛"之道1. 不要追求完美&#xff0c;先动手再说2. 从简单的MapReduce开始3. 利用大模型加速学习4. 循序渐进&#xff0c;建立知识体系 构建您的Hadoop技能树1. 夯实基础&#xff1a;Linux和Java2. 深入理解HDFS3.…

AI 应用还没有大量出现,缺什么?缺聊天机器人编程语言 | Chatopera

只有帮助人发挥创意的才是大市场 现在是需要大量的 AI 应用了。如何产生大量的 AI 应用呢&#xff1f;当年乔布斯说&#xff0c;他看到了个人电脑的两个趋势&#xff0c;一个是图形化用户界面&#xff0c;一个是面向对象编程语言。今天&#xff0c;AI 应用也是新的【图形用户界…

【QT】label中添加QImage图片并旋转(水平翻转、垂直翻转、顺时针旋转、逆时针旋转)

目录 0.简介 1.详细代码及解释 1&#xff09;原label显示在界面上 2&#xff09;水平翻转 3&#xff09;垂直翻转 4&#xff09;顺时针旋转45度 5&#xff09;逆时针旋转 0.简介 环境&#xff1a;windows11 QtCreator 背景&#xff1a;demo&#xff0c;父类为QWidget&a…

Cisco 路由重发布 —— 实现路由信息在不同路由选择域间的传递

一、技术背景 在实际的组网中&#xff0c;可能会遇到这样一个场景&#xff1a;在一个网络中同时存在两种或者两种以上的路由协议。例如客户的网络原先是纯 Cisco 的设备&#xff0c;使用 EIGRP 协议将网络的路由打通。但是后来网络扩容&#xff0c;增加了一批华为的设备&#…

应用层——HTTP

像我们电脑和手机使用的应用软件就是在应用层写的&#xff0c;当我们的数据需要传输的时候换将数据传递到传输层。 应用层专门给用户提供应用功能&#xff0c;比如HTTP,FTP… 我们程序员写的一个个解决我们实际的问题都在应用层&#xff0c;我们今天来聊一聊HTTP。 协议 协议…

【接口自动化_12课_基于Flask搭建MockServer】

知识非核心点&#xff0c;面试题较少。框架搭建的过程中的细节才是面试要点 第三方接口&#xff0c;不方便进行测试&#xff0c; 自己要一个接口去进行模拟。去作为我们项目访问模拟接口。自己写一个接口&#xff0c;需要怎样写 一、flask:轻量级的web应用的框架 安装命令 …

旧系统的会员信息如何导入新系统?

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

数据库相关概念

MySQL 启动停止 MySQL安装完成之后&#xff0c;在系统启动时&#xff0c;会自动启动MySQL服务&#xff0c;无需手动启动。 手动的通过指令启动停止&#xff0c;以管理员身份运行cmd&#xff0c;进入命令行执行如下指令&#xff1a; net start mysql80 net stop mysql80 注意 …

JMeter使用小功能-(持续更新)

1、jmeter在同一个线程组内&#xff0c;uuid的复用 方式一&#xff1a; 方式二&#xff1a; 2、获得jMeter使用的线程总数 ctx.getThreadGroup().getNumberOfThreads()来表示活动线程总数 int threadNumctx.getThreadGroup().getNumThreads(); String threads Integer…

机械学习—零基础学习日志(高数05——函数概念与特性)

零基础为了学人工智能&#xff0c;真的开始复习高数 本小节讲解隐函数&#xff0c;有点神奇&#xff0c;我竟然完全没有隐函数记忆了。 隐函数 隐函数&#xff0c;我个人通俗理解就是&#xff0c;在复杂的环境里&#xff0c;发现纯净天地。例如&#xff0c;在外太空的某个大陆…

工信部信通院首份全景图 | 天空卫士产品26个版块多覆盖

近日&#xff0c;2024全球数字经济大会——数字安全生态建设专题论坛在北京成功举办&#xff0c;论坛由全球数字经济大会组委会主办&#xff0c;中国信息通信研究院和公安部第三研究所共同承办。论坛上&#xff0c;中国信息通信研究院隆重推出了业界首期《数字安全护航技术能力…

Flink集群搭建

&#xff08;1&#xff09;JAVA_HOME 配置 conf/flink-conf.yaml env.java.home &#xff08;2&#xff09;与Hadoop关联&#xff0c;如果确认使用Hadoop相关功能&#xff0c;需要关注对应的版本。如果不使用&#xff0c;则随意 使用flink版本 下载最新版本后&#xff0c;将存…

(四)原生js案例之手风琴效果

手风琴效果也是业务开发中一个比较常见的效果,类似QQ那样的折叠功能 效果预览 代码实现 必要的css * {margin: 0;padding: 0;}body {height: 100vh;background: linear-gradient(200deg, #ffff00 0%, #ee82ee 100%);overflow: hidden;}ul {list-style: none;}#List {margin:…

Stable Diffusion:质量高画风清新细节丰富的二次元大模型二次元插图

今天和大家分享一个基于Pony模型训练的二次元模型&#xff1a;二次元插图。关于该模型有4个不同的分支版本。 1.5版本&#xff1a;loar模型&#xff0c;推荐底模型niji-动漫二次元4.5。 xl版本&#xff1a;SDXL模型版本 mix版本&#xff1a;光影减弱&#xff0c;减少SDXL版本…

C/C++ yaml 库

文章目录 一、yaml 介绍1.1 yaml 介绍1.2 yaml 教程1.3 yaml 在线工具1.4 yaml 出现背景 二、C/C yaml 库选型2.2 libfyaml2.3 yaml-cpp 一、yaml 介绍 1.1 yaml 介绍 YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种人类可读的数据序列化格式&#xff0c;通…

模型训练中出现loss为NaN怎么办?

文章目录 一、模型训练中出现loss为NaN原因1. 学习率过高2. 梯度消失或爆炸3. 数据不平衡或异常4. 模型不稳定5. 过拟合 二、 针对梯度消失或爆炸的解决方案1. 使用torch.autograd.detect_anomaly()2. 使用 torchviz 可视化计算图3. 检查梯度的数值范围4. 调整梯度剪裁 三、更具…

uni-app开发日志:unicloud使用时遇到的问题解决汇总(不断补充)

插件安装后提示与原数据库表冲突&#xff08;2024.7.18&#xff09; 安装uni-admin后再安装uni-cms&#xff0c;在uni-admin中添加好菜单&#xff0c;结果提示该错误 回到hbuilder中uniCloud/database中找到冲突的部分 比较一下&#xff0c;选中老的删除 opendb-news-articl…

HarmonyOS根据官网写案列~ArkTs从简单地页面开始

Entry Component struct Index {State message: string 快速入门;build() {Column() {Text(this.message).fontSize(24).fontWeight(700).width(100%).textAlign(TextAlign.Start).padding({ left: 16 }).fontFamily(HarmonyHeiTi-Bold).lineHeight(33)Scroll() {Column() {Ba…

eclipse免安装版64位 2018版本

前言 eclipse是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言&#xff0c;它只是一个框架和一组服务&#xff0c;用于通过插件组件构建开发环境。 一、下载地址 下载地址&#xff1a;http://source/download 选择如下图红色框文件内容下载 二、安装步骤 1、…