初识优先级队列与堆

1.优先级队列

        由前文队列queue可知,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,在此情况下,使用队列queue显然不合适,

        同时在我们生活场景中也有类似于这中优先事情处理的情况,在医院看病的时候大家都在排队,突然有一个头上插了一把刀的老爷爷也来排队,这时候虽然大家都很急着去看病,但是出于老爷爷情况紧急,所以大家都会默认让老爷爷优先去见医生,而不是让老爷爷按照一般的规则去老老实实的排队;

        考虑到随时会遇到上述这种情况,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)

2.初识堆

        JDK1.8中的PriorityQueue底层使用了这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整。

2.1 堆的概念

        如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一 个一维数组中,并满足:Ki = K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大 堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质

  • 堆中某个节点的值总是不大于或不小于其父节点的值;

  • 堆总是一棵完全二叉树。

2.1.1 小根堆 

                       

        如上图小根堆的逻辑结构所示,在一颗大的完全二叉树中的小二叉树中,该小二叉树的根节点远远小于该树左右子节点,且这时候不考虑左右子节点的数值哪个大;

2.1.2 大根堆

                

         如上图大根堆的逻辑结构所示,给一颗大的完全二叉树中的小二叉树中,该小二叉树的根节点远远大于于该树左右子节点,且这时候不考虑左右子节点的数值哪个大;

2.2 堆的存储方式

        从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,如下图所示堆的存储图解;(堆是将一个一维数组中的数据按照层序遍历的规则将这些数据存储到一个完全二叉树里的完全二叉树)

        注意:由该图中的逻辑结构和存储结构可知,对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了通过一维存储结构能够还原二叉树,一维存储空间中必须要存储空节点,就会导致该存储空间利用率比较低。

         将元素存储到数组中后,可以根据本主初识二叉树章节的性质5对树进行还原。

        假设i为节点在数组中的下标,则有:

        如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2

        如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子

        如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子 

2.3 堆的创建(小根堆)

2.3.1 堆向下调整

        思考:

        对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如何将其创建成堆,首先按照堆的规则将以上数剧放入到完全二叉树里面,如下图所示:

                                 

        仔细观察上图后发现:当前根节点27的左右子树已经完全满足堆的性质,因此只需将根节点向下调整好即可。

        调整过程如下:

1. 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)

2. 如果parent的左孩子存在,即:child < size, 进行以下操作,直到parent的左孩子不存在         2.1parent右孩子是否存在,存在找到左右孩子中最小的孩子,让child进行标

     2.2将parent与较小的孩子child比较,如果:

                2.2.1 parent小于较小的孩子child,调整结束

                2.2.2 否则:交换parent与较小的孩子child,交换完成之后,parent中大的元素向下移动,可能导致子树不满足对的性质,因此需要继续向下调整,即parent = child;child = parent*2+1(左子树); 然后继续2

        详细调整图解如下图所示:

2.3.2 小根堆代码实现

package com.bit.demo1;

public class MySmallHeap {
        public void shiftDown(int[] array, int parent) {
            //child和parent时数组存储的节点的索引
            // child先标记parent的左孩子,因为parent可能右左没有右
            int child = 2*parent + 1;
            int size = array.length;//所有节点的数目
            while(child < size ) {
                //主要保证当前访问到的child都在所有节点的范围内,是有效的

                //child+1是二叉树的最后一个节点
                // 如果右孩子存在,找到左右孩子中较小的孩子,用child进行标记
                if(child + 1 < size) {
                    if(array[child + 1] < array[child]) {
                        child = child + 1;
                    }
                }
                // 如果最小的孩子比其父亲还小,说明该结构没有满足堆的特性,进行交换
                if(array[child] < array[parent]) {
                    int tmp = array[parent];
                    array[parent] = array[child];
                    array[child] = tmp;
                } else {
                    //满足就退出循环
                    break;
                }
                // parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整
                parent = child;
                child = 2*parent + 1;
            }
        }
    }


2.3.3 小根堆代码测试

 public static void main(String[] args) {
        MySmallHeap mySmallHeap = new MySmallHeap();
                int[] array = {27,15,19,18,28,34,65,49,25,37};
                System.out.println("调整前:");
                for(int i = 0; i < array.length ; i++) {
                    System.out.print(array[i] + " ");
                }

                for(int parent = (array.length-2)/2 ; parent >= 0; parent --) {
                    mySmallHeap.shiftDown(array, parent);
                }
                System.out.println();
                System.out.println("调整后:");
                for(int i = 0; i < array.length ; i++) {
                    System.out.print(array[i] + " ");
                }
                System.out.println();
            }

        关于最初的parent索引 ?

        测试结果如下图所示:

         注意:在调整以parent为根的二叉树时,必须要满足parent的左子树和右子树已经是堆了才可以向下调整。

        最坏的情况即图示的情况,从根一路比较到叶子,比较的次数为完全二叉树的高度,即时间复杂度为

2.4 建堆的时间复杂度

2.4.1 建堆的步骤图解

        对于普通的序列{ 1,5,3,8,7,6 },我们需要建立大堆,即根节点的左右子树不满足堆的特性,又该如何调整呢,其中里面的细节如下:

        大概思路:

        找倒数第一个非叶子节点(最右侧的最小子树根节点),从该节点位置开始往前进行按照根堆的规则运作,一直运作到根节点,这时候才确定根节点的数值;

        因为为了根节点导致下面的不同子树的结构都发生了变化,所以接下来确定索引为1的根节点的数字,这样就需要重复上述的步骤;

        就这样重复上面两个步骤,知道确定最右侧最小子树的根节点(索引为(arr.length-2)/2)的数值,我们的整体过程才算结束;

2.4.2 时间复杂度求解图解

        至此可得:建堆的时间复杂度为O(N)

ps:本次的内容就到这里了,如果喜欢的话就请一键三连哦!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git clone 命令

git clone 是一个用于克隆&#xff08;clone&#xff09;远程 Git 仓库到本地的命令。 git clone 可以将一个远程 Git 仓库拷贝到本地&#xff0c;让自己能够查看该项目&#xff0c;或者进行修改。 git clone 命令&#xff0c;你可以复制远程仓库的所有代码和历史记录&#xf…

python基于轻量级GhostNet模型开发构建23种常见中草药图像识别系统

轻量级识别模型在我们前面的博文中已经有过很多实践了&#xff0c;感兴趣的话可以自行移步阅读&#xff1a; 《移动端轻量级模型开发谁更胜一筹&#xff0c;efficientnet、mobilenetv2、mobilenetv3、ghostnet、mnasnet、shufflenetv2驾驶危险行为识别模型对比开发测试》 《基…

目标检测——OverFeat算法解读

论文&#xff1a;OverFeat: Integrated Recognition, Localization and Detection using Convolutional Networks 作者&#xff1a;Pierre Sermanet, David Eigen, Xiang Zhang, Michael Mathieu, Rob Fergus, Yann LeCun 链接&#xff1a;https://arxiv.org/abs/1312.6229 文章…

【kubernetes】k3s集群搭建(正在更新……)

文章目录 一、k3s简介二、快速搭建1.控制平面2.镜像加速 Pod容器集1.创建和管理pod Deployment(部署)与ReplicaSet(副本集)滚动更新 Service命名空间YAML语法管理对象常用命令缩写YAML规范 声明式配置对象标签选择器 容器运行时接口(CRI)与镜像导入导出容器运行时接口(CRI) 金丝…

C语言期末考试复习PTA数据类型及表达式-分支结构程序-循环结构-数组经典选择题

目录 第一章&#xff1a;C语言数据类型和表达式 第一题&#xff1a; 第二题&#xff1a; 第三题&#xff1a; 第四题&#xff1a; 第五题&#xff1a; 第六题&#xff1a; 第七题&#xff1a; 第八题&#xff1a; 第九题&#xff1a; 第二章&#xff1a;分支结构程序…

2023.12.7 关于 MySQL 事务详解

目录 事务的四大特性 原子性 一致性 持久性 隔离性 事务并发执行 脏读 不可重复读 幻读 四个隔离级别 read uncommitted read committed repeatable read serializable 事务的四大特性 原子性 一个事务中的所有操作&#xff0c;要么全部完成&#xff0c;要么全部…

一篇文章带你快速入门 Nuxt.js 服务端渲染

1. Nuxt.js 概述 1.1 我们一起做过的SPA SPA&#xff08;single page web application&#xff09;单页 Web 应用&#xff0c;Web 不再是一张张页面&#xff0c;而是一个整体的应用&#xff0c;一个由路由系统、数据系统、页面&#xff08;组件&#xff09;系统等等&#xff0…

16mic圆形麦克风阵列电路与声源定位算法设计

16mic圆形麦克风阵列电路与声源定位算法设计 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)&#xff1f;可加我微信hezkz17, 本群提供音频技术答疑服务&#xff0c;群赠送语音信号处理降噪算法&#xff0c;蓝牙耳机音频&#xff0c;DSP音频项目核心开发资料, 1 实…

多线程并发Ping脚本

1. 前言 最近需要ping地址&#xff0c;还是挺多的&#xff0c;就使用python搞一个ping脚本&#xff0c;记录一下&#xff0c;以免丢失了。 2. 脚本介绍 首先检查是否存在True.txt或False.txt文件&#xff0c;并在用户确认后进行删除&#xff0c;然后从IP.txt的文件中读取IP地…

灵活性与可靠性:SaaS云开发与定制开发小程序的优缺点解析

随着移动互联网的快速发展&#xff0c;微信小程序作为一种轻量级的应用程序&#xff0c;逐渐成为了企业开展业务和提升用户体验的重要工具。对于企业而言&#xff0c;选择通过SaaS云开发或定制开发的方式开发小程序&#xff0c;都是为了更好地实现业务目标。在这篇文章中&#…

【数据结构】插入排序,希尔排序,选择排序,堆排序,冒泡排序

1.插入排序 思路&#xff1a;插入排序将一个数插入一个有序的数组里面&#xff0c;将这个数和数组元素挨着比较&#xff0c;直到他插入到合适的位置。 动画演示&#xff1a; 步骤&#xff1a;1.定义一个变量tmp保存要插入的数据 2.在循环中用tmp和有序数组中的元素比较&#…

Spring全面详解

目录 1. Spring 概述 1.1 Spring是什么 1.2 Spring的作用 1.3 Spring IoC是什么 2. Spring 快速入门 3. Spring Bean 3.1 的实例化方式 空参构造器 3.2 的属性注入 全参构造器注入 setter方法注入 策略模式 3.3 注解管理 3.4 注解方式的属性注入 1. Spring 概述 …

聚类分析 | Matlab实现基于谱聚类(Spectral Cluster)的数据聚类可视化

聚类分析 | Matlab实现基于谱聚类(Spectral Cluster)的数据聚类可视化 目录 聚类分析 | Matlab实现基于谱聚类(Spectral Cluster)的数据聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于谱聚类(Spectral Cluster)的聚类算法可视化&#xff08;完…

计算机毕业设计 基于SpringBoot的高校毕业与学位资格审核系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Facebook自动回复脚本编写教程

在数字时代&#xff0c;社交媒体已经成为人们交流和建立联系的重要渠道&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;拥有数十亿的用户&#xff0c;为企业和个人提供了无限的社交可能性。 然而&#xff0c;对于企业和个人来说&#xff0c;在Facebook上保持…

整合消息队列RabbitMQ

为什么使用消息队列MQ&#xff1f; 因为使用消息队列有多个好处&#xff1a;可以实现系统服务的解耦、异步和削峰&#xff1a; 异步通信&#xff1a;消息队列提供了一种异步通信的方式&#xff0c;发送方可以将消息发送到队列中&#xff0c;然后继续执行其他任务&#xff0c;…

C++STL的string模拟实现

文章目录 前言string的成员变量成员函数构造函数拷贝构造赋值重载 模拟实现string各种接口print迭代器普通迭代器const迭代器 string比较大小push_backinsert 和 eraseinserterase reserve和resizereserveresize swapfindcout和cincoutcin 前言 今天要讲string的底层实现&…

docker---资源控制

docker的资源控制 对容器使用宿主机的资源进行限制。 三种控制方向&#xff1a;CPU 内存 磁盘I/O docker使用linux自带的功能cgroup&#xff1b;control groups是linux内核系统提供的一种可以限制记录&#xff0c;隔离进程所使用的物理资源机制。 docker借助此…

每日一练 | 华为认证真题练习Day145

1、一台路由器通过RIP、OSPF和静态路由都学习到了到达同一目的地址的路由。默认情况下&#xff0c;VRP将最终选择通过哪种协议学习到的路由&#xff1f; A. 三种协议学习到的路由都选择 B. 静态路由 C. OSPF D. RIP 2、如果网络管理员没有配置骨干区域&#xff0c;则路由器…

el-table 表格多选(后端接口搜索分页)实现已选中的记忆功能。实现表格数据和已选数据(前端分页)动态同步更新。

实现效果&#xff1a;&#xff08;可拉代码下来看&#xff1a;vue-demo: vueDemo&#xff09; 左侧表格为点击查询调用接口查询出来的数据&#xff0c;右侧表格为左侧表格所有选择的数据&#xff0c;由前端实现分页。 两个el-table勾选数据联动更新 实现逻辑&#xff1a; el-…