【从浅到深的算法技巧】优先队列

5.6 优先队列

许多应用程序都需要处理有序的元素,但不一定要求它们全部有序, 或是不一定要一次就将它们排序。很多情况下我们会收集一些元素, 处理当前键值最大的元素,然后再收集更多的元素,再处理当前键值最大的元素,如此这般。例如,你可能有一台能够同时运行多个应用程序的电脑(或者手机)。这是通过为每个应用程序的事件分配一个优先级, 并总是处理下一个优先级 最高的事件来实现的。例如,绝大多数手机分配给来电的优先级都会比游戏程序的高。

在这种情况下,类型叫做优先队列。优先队列的使用和队列(删除最老的元素)以及栈(删除最新的元素)类似,但高效地实现它则更有挑战性。

我们先简单地讨论优先队列的基本表现形式(都能在线性时间内完成)之后,我们会学习基于二叉堆数据结构的一种优先队列的经典实现方法定条件排序,以实现高效地(对数级别的)删除最大元素和插入元素操作。

优先队列的一些重要的应用场景包括模拟系统,其中事件的键即为发生的时间,而系统需要按照时间顺序处理所有事件:任务调度,其中键值对应的优先级决定了应该首先执行哪些任务:数值计算,键值代表计算错误,而我们需要按照键值指定的顺序来修正它们。个具体的例子,展示优先队列在粒子碰撞模拟中的应用。

通过插入一列元素然后个个地删掉其中最小的元素,我们可以用优先队列实现排序算法。一种名为堆排序的重要排序算法也来自于基于堆的优先队列的实现。

5.6.1 API

优先队列是种抽象数据类型 ,它表示了一组值和对这些值的操作,它的抽象层使我们能够方便地将应用程序(用例)和我们将在本节中学习的各种具体实现隔离开来。我们会详细定义一组应用程序编程接口 (API)来为数据结构的用例提供足够的信息。 优先队列最重要的操作就是删除最大元素和插入元素,所以我们会把精力集中在它们身上。删除最大元素的方法名为deMax(),插人元素的方法名为insert()。按照惯例,我们只会通过辅助函数less()来比较两个元素,和排序算法一样。 如果允许重复元素,最大表示的是所有最大元素之一。 为了将API定义完整,我们还需要加入构造函数(和我们在栈以及队列中使用的类似)和一个空队列测试方法。为了保证灵活性,我们在实现中使用了泛型,将实现了Comparable接口的数据的类型作为参数Key。这使得我们可以不必再区别元素和元素的键,对数据类型和算法的描述也将更加清断和简洁。例如,我们将用“最大元素"代替“最大键值”或是“键值最大的元素”

泛型优先队列的 API
public class MaxPQ<Key extends Comparable
MaxPQ()创建一个优先队列
MaxPQ(int max)创建一个最大容量为max的优先队列
public class MaxPQ<key extends Comparable
MaxPQ(Key[] a)用a[]中的元素创建个优先队列
void Insert(Key v)向优先队列中插入一个元素
Key max()返回最大元索
Key delMax()删除并返回最大元素
boolean isEmpty()返回队列是否为空
int size()返回优先队列中的元素个数

为了用例代码的方便,API包含的三个构造函数使得用例可以构造指定大小的优先队列(还可以用给定的一个数组将其初始化)。为了使用例代码更加清晰,我们会在适当的地方使用另一个类MinPQ。它和MaxPQ类似,只是含有一一个delMin()方法来删除并返回队列中键值最小的那个元素。MaxPQ的任意实现都能很容易地转化为MinPQ的实现,反之亦然,只需要改变一下less()比较的方向即可。

优先队列的调用示例

为了展示优先队列的抽象模型的价值,考虑以下问题:输入N个字符串,每个字符串都对映着一个整数,你的任务就是从中找出最大的(或是最小的) M个整数(及其关联的字符串)。这些输入可能是金融事务,你需要从中找出最大的那些;或是农产品中的杀虫剂含量,这时你需要从中找出最小的那些;或是服务请求、科学实验的结果,或是其他应用。在某些应用场景中,输入量可能非常巨大,甚至可以认为输人是无限的。解决这个问题的一种方法是将输入排序然后从中找M个最大的元素,但我们已经说明输人将会非常庞大。另一种方法是将每个新的输入和已知的M个最大元素比较,但除非M较小,否则这种比较的代价会非常高昂。只要我们能够高效地实现insert()和delMin(),下面的优先队列用例中调用了MinPQ的TopM就能使用优先队列解决这个问题,这就是本节中我们的目标。在现代基础性计算环境中超大的输入N非常常见,这些实现使我们能够解决以前缺乏足够资源去解决的问题,如下表所示。

从N个输入中找到最大的M个元素所需成本
示例时间空间
排序算法的用例MogNM
调用初级实现的优先队列NMM
调用基于堆实现的优先队列NlogMM
一个优先队列的用例
public class TopM{public static void main(String[] args){//打印输入流最大的M行int M = Integer. parseInt(args[0]);MinPQ<Transaction> pq = new MinPQ<Transaction>(M+1);while (StdIn.hasNextLine(){//为下一行输入创建一个元素并放入优先队列中pq.insert(new Transaction(StdIn.readLine()));if (pq.size() > M){pq. delMin();//如果优先队列中存在M+1个元素则删除其中最小的元素}//最大的M个元素都在优先队列中Stack<Transaction> stack = new Stack<Transaction>();while(!pq.isEmpty())  stack.push(pq. delMin);for(Transaction t : stack )  System.out.println(t);}}}

从命令行输入一个整数M以及一系列字符申, 每一行表示一个事务。这段代码调用了MimPQ并会打印数字最大的M行。它用到了Transaction类,构造了一个用数字作为键的优先队列。当优先队列的大小超过M时就删掉其中最小的元素。所有事务输人完毕之后程序会从优先队列中按递减顺序打印出最大的M个事务。这段代码相当于将所有事务放入一个栈,遍历栈以颠倒它们的顺序并按照增序将它们打印出来。

5.6.2 初级实现

4种基础数据结构是实现优先队列的起点。我们可以使用有序或无序的数组或链表。在队列较小时,大量使用两种主要操作之一时, 或是所操作元素的顺序已知时,它们十分有用。

5.6.2.1 数组实现(无序)

或许实现优先队列的最简单方法就是基于2.1节中下压栈的代码。insert()方法的代码和栈的push()方法完全一样。要实现删除最大元素,我们可以添加一段类似于选择排序的内循环的代码,将最大元素和边界元素交换然后删除它,和我们对栈的pop()方法的实现一样。 和栈类似,我们也可以加人调整数组大小的代码来保证数据结构中至少含有四分之一的元素而又永远不会溢出。

5.6.2.2 数组实现 (有序)

另一种方法就是在insert()方法中添加代码,将所有较大的元素向右边移动-格以使数组保持有序(和插入排序一样)。这样,最大的元素总会在数组的一边,优先队列的删除最大元素操作就和栈的pop()操作一样了。

5.6.2.3 链表表示法

和刚才类似,我们可以用基于链表的下压栈的代码作为基础,而后可以选择修改pop()来找到并返回最大元素,或是修改push()来保证所有元素为逆序并用pop()来刪除并返回链表的首元素(也就是最大的元素)。

使用无序序列是解决这个问题的情性方法,我们仅在必要的时候才会采取行动(找出最大元素)使用有序序列则是解决问题的积极方法,因为我们会尽可能未雨绸缪(在插人元素时就保持列表有序),使后续操作更高效。

实现栈或是队列与实现优先队列的最大不同在于对性能的要求。对于栈和队列,我们的实现能够在常数时间内完成所有操作;而对于优先队列,我们刚刚讨论过的所有初级实现中,插入元素和删除最大元素这两个操作之一在最坏情况下需 要线性时间来完成(如下表所示)。我们接下来要讨论的基于数据结构堆的实现能够保证这两种操作都能更快地执行。

优先队列的各种实现在 最坏情况下运行时间的增长数量级
数据结构插入元素删除最大元素
有序数组N1
无序数组1N
logNlogN
理想情况11

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

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

相关文章

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏5(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言修改鼠标光标和中心提示图鼠标光标素材修改默认鼠标光标修改中心提示图 拾取提示弹窗简单绘制UI拾取弹窗功能 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使…

canvas的一些基础

在 Canvas 中&#xff0c;基本图形有两种&#xff1a;直线图形和曲线图形 直线图形&#xff1a;直线、矩形(描边矩形和填充矩形)、多边形 曲线图形&#xff1a;曲线和弧线&#xff08;弧线是圆的一部分&#xff0c;曲线则不一定&#xff0c;弧线上的每个点都具有相同的曲率&…

3D Gaussian Splatting-实时辐射场渲染技术

引用自&#xff1a;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/3d_gaussian_splatting_high.pdf 概述&#xff1a; 该论文介绍了一种用于实时辐射场渲染的3D高斯点渲染技术。 其基本原理是&#xff1a; 一&#xff1a;首先从SfM校准的图像及其对应的稀疏点云…

十分钟快速上手Spring Boot与微信小程序API接口的调用,快速开发小程序后端服务

1.1 微信小程序API接口介绍 微信小程序API接口是连接小程序前端与后端服务器的桥梁&#xff0c;它提供了丰富的功能接口&#xff0c;包括用户信息、支付、模板消息、数据存储等。这些API接口能够满足开发者在小程序中实现各种复杂业务逻辑的需求。 用户信息接口 用户信息接口…

计算机服务器中了locked勒索病毒怎么办,locked勒索病毒解密流程

随着网络技术在企业生产生活中的应用&#xff0c;越来越多的企业开始走向数字化办公模式&#xff0c;极大地提升了企业办公与生产效率&#xff0c;而其中的企业数据起到了关键性作用&#xff0c;企业的数据安全是众多企业关心的话题。但网络是一把双刃剑&#xff0c;近期&#…

【C++】开源:Windows图形库EasyX配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Windows图形库EasyX配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#…

【 USRP 相控阵】ADAR1000 : 4 通道 X 频段和 Ku 频段波束形成器,8 GHz 至 16 GHz

介绍 ADAR1000 是一款适用于相控阵的 4 通道 X 和 Ku 频段波束形成内核芯片。此器件在接收和发射模式之间以半双工状态工作。在接收模式下&#xff0c;输入信号通过四个接收通道后在公共 RF_IO 引脚上组合在一起。在发射模式下&#xff0c;RF_IO 输入信号拆分后通过四个发射通…

Linux 指令 第二弹

1 查看文件系统空间 1.1 查看文件系统磁盘使用情况 df df -h 显示所有挂载的文件系统的信息&#xff0c;包括使用情况和可用空间。 -h 的意思是以人类可读方式显示 1.2 查看某个文件夹的磁盘使用 du du -h /path/to/yourdirectory1.3 ls ls -lh /path/to/yourdirectory显示…

智慧食堂预点餐管理系统-计算机毕业设计源码48846

摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;餐饮业当然也不例外。智慧食堂预点餐管理系统小程序是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&…

回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于OOA-LSSVM鱼鹰算法优化最小支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于OOA-LSSVM鱼鹰算法优化最小…

C++关键词auto详解

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、小思考 随着我们对于C的不断学习&#xff0c;遇到的程序越来越复杂&#xff0c;程序中用到的类型也越来越复杂…

java接口练习

首先&#xff0c;明确&#xff1a;接口可以提供模糊的方法&#xff0c;方案&#xff1b;那么具体的实现需要另外创建实现类去实现&#xff1b; 另外&#xff1a;明确接口的特点&#xff1a;接口回调&#xff0c;接口的多态性&#xff1b; 具体解释&#xff1a; 接口的特点&a…

转转基于MQ的分布式重试框架设计方案

文章目录 1 背景2 方案3 效果4 可选项5 注意事项6 总结 1 背景 在分布式场景下&#xff0c;为了保障系统的可用性和数据的最终一致性&#xff0c;采用基于消息队列&#xff08;MQ&#xff09;的重试机制是一种常见的解决方案。伪代码如下&#xff1a; /*** 需要保证最终一致性…

phpstudy安装并运行redis

对于一个菜鸟来说&#xff0c;任何一个小步骤都可能研究半天&#xff0c;比如“phpstudy安装并运行redis”这一问题&#xff0c;解决好后第一时间记录下来&#xff0c;方便日后查看&#xff0c;也为遇到同样困难的小伙伴提供个参考&#xff01; 一、phpstudy安装redis 1.打开…

打车代驾APP小程序开发功能有哪些?

随着移动互联网的快速发展&#xff0c;越来越多的人开始使用网约车服务。开发一个网约车、打车、叫车系统已经成为了市场的热门需求。 随着城市化进程的加速和人们出行方式的多样化&#xff0c;传统的公共交通方式已经无法满足人们的出行需求。同时&#xff0c;私家车拥有成本也…

【计算机视觉】万字长文详解:卷积神经网络

以下部分文字资料整合于网络&#xff0c;本文仅供自己学习用&#xff01; 一、计算机视觉概述 如果输入层和隐藏层和之前一样都是采用全连接网络&#xff0c;参数过多会导致过拟合问题&#xff0c;其次这么多的参数存储下来对计算机的内存要求也是很高的 解决这一问题&#x…

PostgreSql和Oracle的事务机制区别以及对程序的影响

前言 几年前IT信息产业的一些核心技术包括架构、产品以及生态都是国外制定&#xff0c;然而自从“遥遥领先”公司被制裁后&#xff0c;国家开始大力支持信息产业“新基建”&#xff0c;自2020年开始市场上涌现出了大量的国产化软件&#xff0c;就国产化数据库而言我所在的公司…

辽宁链家新房数据采集与可视化实现

摘 要 网络爬虫也叫做网络机器人&#xff0c;是一种按照一定的规则&#xff0c;自动地抓取网络信息&#xff0c;进行数据信息的采集与整理的程序或者脚本。随着海量数据的出现&#xff0c;如何快速有效的获取到我们想要的数据成为难题。以房源信息为例&#xff0c;该文使用Pyt…

做虾皮Shopee想高效发货?EasyBoss ERP的这个功能你不能错过!

随着业务的发展&#xff0c;许多Shopee、Lazada卖家的店铺订单量逐渐增大、仓库商品的SKU也越来越多。在这种情况下&#xff0c;一些卖家会选择采用人海战术来提高拣货、发货的效率。效率提高的同时&#xff0c;也意味着企业的用人成本的增加&#xff01; 那么&#xff0c;如何…

Java进阶:集合进阶统计次数(双列集合HashMap 单列集合Set):实现景点被选择的次数统计

~ 景点次数统计 * 某个班级80名学生&#xff0c;现在需要组成秋游活动&#xff0c;* 班长提供了四个景点依次是&#xff08;A,B, C, D&#xff09;&#xff0c;* 每个学生只能选择一个景点&#xff0c;请统计出最终那个景点想去的人数最多*/代码示例&#xff1a; public static…