Java学数据结构(4)——PriorityQueue(优先队列) 二叉堆(binary heap)

在这里插入图片描述

前言

数据结构与算法作为计算机科学的基础,是一个重点和难点,在实际编程中似乎看不它们的身影,但是它们有随处不在,如影随形。

本系列博客是《数据结构与算法分析—Java语言描述》的读书笔记,合集文章列表如下:

数据结构与算法(Data Structures and Algorithm)——跟着Mark Allen Weiss用Java语言学习数据结构与算法

本篇博客介绍二叉堆(binary heap),它的使用对于PriorityQueue(优先队列)的实现相当普遍,以至于当堆(heap)这个词不加修饰地用在优先队列的上下文中时,一般都是指数据结构的这种实现。

在这里插入图片描述

其他相关的本书的学习笔记博客文章列表如下:

  • Java学数据结构(1)——抽象数据类型ADT & 表List、栈Stack和队列Qeue

  • Java学数据结构(2)——树Tree & 二叉树binary tree & 二叉查找树 & AVL树 & 树的遍历

  • Java学数据结构(3)——树Tree & B树 & 红黑树 & Java标准库中的集合Set与映射Map & 使用多个映射Map的案例

  • Java学数据结构(4)——散列表Hash table & 散列函数 & 哈希冲突

目录

  • 前言
  • 引出
  • 优先队列(堆)
  • 二叉堆
    • 结构性质
    • 堆序性质
  • 堆的基本操作
    • 插入元素 (上滤percolate up)
    • 删除最小元素
  • 总结

引出


1.PriorityQueue(优先队列)是一种特殊的队列数据结构,其中每个元素都有一个优先级;
2.insert(插入)和deleteMin(删除最小者)的方式;

优先队列(堆)

虽然发送到打印机的作业一般被放到队列中,但这未必总是最好的做法。例如,可能有一项作业特别重要,因此希望只要打印机一有空闲就来处理这项作业。反之,若在打印机有空时正好有多个单页的作业及一项100页的作业等待打印,则更合理的做法也许是最后处理长的作业,尽管它不是最后提交上来的(不幸的是,大多数的系统并不这么做,有时可能特别令人懊恼)。

类似地,在多用户环境中,操作系统调度程序必须决定在若干进程中运行哪个进程。一般一个进程只被允许运行一个固定的时间片。一种算法是使用一个队列。开始时作业被放到队列的末尾。调度程序将反复提取队列中的第一个作业并运行它,直到运行完毕,或者该作业的时间片用完,并在作业未运行完毕时把它放到队列的末尾。

这种策略一般并不太合适,因为一些很短的作业由于一味等待运行而要花费很长的时间去处理。一般说来,短的作业要尽可能快地结束,这一点很重要,因此在已经运行的作业当中这些短作业应该拥有优先权。此外,有些作业虽不短小但很重要,也应该拥有优先权。这种特殊的应用似乎需要一类特殊的队列,我们称之为优先队列(priority queue)。

  • 优先队列ADT的有效实现。
  • 优先队列的使用。
  • 优先队列的高级实现

我们将看到的这类数据结构属于计算机科学中最精致的一种

PriorityQueue(优先队列)是一种特殊的队列数据结构,其中每个元素都有一个优先级。在PriorityQueue中,元素按照优先级的顺序进行排序,具有最高优先级的元素最先被取出。

下面是一些PriorityQueue的应用案例:

  1. 任务调度:在一个多任务系统中,每个任务都有不同的优先级。可以使用PriorityQueue来管理任务队列,确保高优先级的任务先被执行。
  2. 事件处理:在事件驱动的系统中,事件可能具有不同的优先级。PriorityQueue可以用于按照优先级处理事件,确保高优先级的事件先被处理。
  3. 路由算法:在网络路由中,路由器需要根据不同的路由策略选择最佳的路径。PriorityQueue可以用于存储和排序路由信息,以便选择最佳路径。
  4. 资源分配:在资源管理系统中,资源可能有不同的优先级和需求。PriorityQueue可以用于按照优先级分配资源,确保高优先级的任务获得足够的资源。
  5. 任务调度器:在操作系统中,任务调度器负责管理和调度进程。PriorityQueue可以用于按照进程的优先级进行调度,确保高优先级的进程先被执行。

这些只是PriorityQueue的一些应用案例,实际上,PriorityQueue在许多领域都有广泛的应用,特别是需要按照优先级进行排序和处理的场景。

在这里插入图片描述

优先队列是允许至少下列两种操作的数据结构:insert(插入),它的作用是显而易见的;以及deleteMin(删除最小者),它的工作是找出、返回并删除优先队列中最小的元素。insert操作等价于enqueue(人队),而deleteMin则是队列运算dequeue(出队)在优先队列中的等价操作。

二叉堆

我们将要使用的这种工具叫作二叉堆(binary heap),它的使用对于优先队列的实现相当普遍,以至于当堆(heap)这个词不加修饰地用在优先队列的上下文中时,一般都是指数据结构的这种实现。在本节,我们把二叉堆只叫作堆。

像二叉查找树一样,堆也有两个性质,即结构性和堆序性。恰似AVL树,对堆的一次操作可能破坏这两个性质中的一个,因此,堆的操作必须到堆的所有性质都被满足时才能终止。事实上这并不难做到。

结构性质

堆是一棵被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。这样的树称为完全二叉树(complete binary tree)。图6-2给出了一个例子

在这里插入图片描述

一个重要的观察发现,因为完全二叉树这么有规律,所以它可以用一个数组表示而不需要使用链。图6-3中的数组对应图6-2中的堆。

在这里插入图片描述

数据结构的分析

在这里插入图片描述

堆序性质

让操作快速执行的性质是堆序性质(heap-order property)。由于我们想要快速找出最小元,因此最小元应该在根上。如果我们考虑任意子树也应该是一个堆,那么任意节点就应该小于它的所有后裔。

在这里插入图片描述

根据堆序性质,最小元总可以在根处找到。因此,我们以常数时间得到附加操作findMin

堆的基本操作

插入元素 (上滤percolate up)

为将一个元素X插入到堆中,我们在下一个可用位置创建一个空穴,否则该堆将不是完全树。如果X可以放在该空穴中而并不破坏堆的序,那么插入完成。否则,我们把空穴的父节点上的元素移人该空穴中,这样,空穴就朝着根的方向上冒一步。继续该过程直到X能被放人空穴中为止。

如图6-6所示,为了插入14,我们在堆的下一个可用位置建立一个空穴。由于将14插入空穴破坏了堆序性质,因此将31移入该空穴。在图6-7中继续这种策略,直到找出置入14的正确位置。

这种一般的策略叫作上滤(percolate up);新元素在堆中上滤直到找出正确的位置。

比如如下的一个堆

在这里插入图片描述

插入元素的流程拆解

在这里插入图片描述

全体流程解析

在这里插入图片描述

package com.tianju.security.dataStructure.head;import java.util.Arrays;
import java.util.List;public class BinaryHeap<AnyType extends Comparable<? super AnyType>> {private AnyType[] array;private int size; // 数组中的元素数量private static final int DEFAULT_CAPACITY =10; // 默认容量为10public BinaryHeap() {}public BinaryHeap(AnyType[] array) {this.array = array;this.size = array.length-1;}public Integer size(){return size;}public void insert(AnyType x){System.out.println("扩容之前:"+size);// 如果放不下,就扩容if (array.length+1>array.length){int newLen = array.length + (array.length>>1);array = Arrays.copyOf(array, newLen);System.out.println("扩容之后:"+array.length);}System.out.println(array[size]);array[size+1]=x;printArr();int currLength = size+1;int forTimes = 0;while (currLength/2!=1){System.out.println("循环次数"+forTimes++);if (array[currLength/2].compareTo(x)>0){// 进行上冒AnyType temp = array[currLength/2];System.out.println("当前"+currLength/2+"位置的元素:"+temp);array[currLength/2] = x;array[currLength] = temp;}currLength=currLength/2;}size++;System.out.println("当前长度:"+size);}public void printArr(){System.out.println();System.out.print("[");StringBuilder s = new StringBuilder("[");for(AnyType x:array){
//            System.out.print(x+", ");s.append(x).append(", ");}for (int i=1;i<size;i++){System.out.print(array[i]+", ");}System.out.print("]");System.out.println();s.append("]");System.out.println(s);}}

在这里插入图片描述

package com.tianju.security.dataStructure.head;import java.util.Arrays;
import java.util.List;public class BinaryTestDemo {public static void main(String[] args) {List<Integer> list = Arrays.asList(0,13,21,16,24,31,19,68,65,26,32);Integer[] array = list.toArray(new Integer[list.size()]);BinaryHeap<Integer> binaryHeap = new BinaryHeap<>(array);binaryHeap.printArr();binaryHeap.insert(14);binaryHeap.printArr();System.out.println(binaryHeap.size());}
}

在这里插入图片描述

在这里插入图片描述

上图的Heap堆插入元素2的流程

在这里插入图片描述

删除最小元素

deleteMin以类似于插入的方式处理。找出最小元是容易的,困难之处是删除它。当删除一个最小元时,要在根节点建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素X必须移动到该堆的某个地方。如果X可以被放到空穴中,那么deleteMin完成。不过这一般不太可能,因此我们将空穴的两个儿子中较小者移入空穴,这样就把空穴向下推了一层。重复该步骤直到X可以被放入空穴中。因此,我们的做法是将X置入沿着从根开始包含最小儿子的一条路径上的一个正确的位置。

在这里插入图片描述


总结

1.PriorityQueue(优先队列)是一种特殊的队列数据结构,其中每个元素都有一个优先级;
2.insert(插入)和deleteMin(删除最小者)的方式;

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

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

相关文章

数据安全防护:云访问安全代理(CASB)

云访问安全代理&#xff08;Cloud Access Security Broker&#xff0c;CASB&#xff09;&#xff0c;是一款面向应用的数据防护服务&#xff0c;基于免应用开发改造的配置方式&#xff0c;提供数据加密、数据脱敏功能。数据加密支持国密算法&#xff0c;提供面向服务侧的字段级…

Springboot+vue的企业OA管理系统(有报告),Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的企业OA管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的企业OA管理系统&#xff0c;采用M&#xff08;m…

【电商API接口的应用:电商数据分析入门】初识Web API(一)

如何使用Web应用变成接口(API)自动请求网站到特定信息而不是整个网站&#xff0c;再对这些信息进行可视化。由于这样编写到程序始终使用最新到数据来生成可视化&#xff0c;因此即便数据瞬息万变&#xff0c;它呈现到信息也都是最新的。 使用Web API Web API是网站的一部分&am…

揭秘 Go 中的 new() 和 make() 函数

Go&#xff08;或 Golang&#xff09;是一种现代、静态类型、编译型的编程语言&#xff0c;专为构建可扩展、并发和高效的软件而设计。它提供了各种内置的函数和特性&#xff0c;帮助开发人员编写简洁高效的代码。其中包括 new() 和 make() 函数&#xff0c;这两个函数乍看起来…

有哪些值得推荐的Java 练手项目?

大家好&#xff0c;我是 jonssonyan 我是一名 Java 后端程序员&#xff0c;偶尔也会写一写前端&#xff0c;主要的技术栈是 JavaSpringBootMySQLRedisVue.js&#xff0c;基于我学过的技术认真的对每个分享的项目进行鉴别&#xff0c;今天就和大家分享我曾经用来学习的开源项目…

【置顶】关于博客的一些公告

所谓 万事开头难&#xff0c;最开始的两个专栏 《微机》 和 《骨骼动作识别》 定价 29.9 &#xff0c;因为&#xff1a; 刚开始确实比较困难&#xff0c;要把自己学的知识彻底搞懂讲给别人&#xff0c;还要 码字排版&#xff0c;从 Markdown 语法开始学起&#xff08;这都是 花…

【Java 进阶篇】CSS 属性

当你学习CSS时&#xff0c;了解CSS属性是非常重要的&#xff0c;因为这些属性控制了网页上元素的外观和布局。本文将详细介绍一些常见的CSS属性&#xff0c;包括文本属性、盒子模型属性、背景和边框属性、定位属性等。我们还将为每个属性提供示例代码&#xff0c;以便你更好地理…

Go 复合类型之字典类型介绍

Go 复合类型之字典类型介绍 文章目录 Go 复合类型之字典类型介绍一、map类型介绍1.1 什么是 map 类型&#xff1f;1.2 map 类型特性 二.map 变量的声明和初始化2.1 方法一&#xff1a;使用 make 函数声明和初始化&#xff08;推荐&#xff09;2.2 方法二&#xff1a;使用复合字…

家政服务行业做开发微信小程序可以实现什么功能

家政服务行业开发微信小程序可以实现多种功能&#xff0c;从而提升服务品质和效率&#xff0c;下面我们来详细介绍一些可能实现的功能。 一、展示服务信息 家政服务微信小程序可以展示各种服务信息&#xff0c;包括各类家政服务项目、价格、服务流程、服务人员信息等。用户可以…

【pycharm】控制台报错:终端无法加载文件\venv\Scripts\activate.ps1

目录 一、在pycharm控制台输入 二、在windows的power shell &#xff08;以管理员方式打开&#xff09; 三、 在pycharm控制台输入 四、重新打开pycharm即可 前言&#xff1a;安装pycharm2022-03版本出现的终端打开报错 一、在pycharm控制台输入 get-executionpolicy …

S7-1200PLC与昆仑通态触摸屏通讯

测试环境&#xff1a;Win10、MCGS、博图V16、1214DCDCDC 博途工控人平时在哪里技术交流博途工控人社群 博途工控人平时在哪里技术交流博途工控人社群 将PLC端做如下配置 1-MCGS配置S7-1200驱动 1.1-添加驱动 双击设备窗口 点击设备组态窗口下的设备管理&#xff0c;选择西门…

Easysearch Chart 0.2.0都有哪些变化

Easysearch Chart 包更新了&#xff0c;让我们来看看都有哪些变化&#xff1a; Docker 镜像升级 Service 名称调整&#xff0c;支持 NodePort 模式部署 现在让我们用 NodePort 模式部署一下&#xff1a; # helm search repo infinilabs NAME CHART VERSION …

Qt元对象系统 day4

Qt元对象系统 day4 元对象 元对象系统是一个基于标准C的扩展&#xff0c;为Qt提供了信号与槽机制、实时类型信息、动态属性系统。元对象可以操作、创建、描述或是执行其他对象&#xff0c;元对象又称为基对象元对象组成 QObject&#xff1a; QT 对象模型的核心&#xff0c;绝…

nginx配置实例-负载均衡

1 实现效果&#xff1a; 浏览器访问nginx&#xff0c;输入访问nginx地址&#xff0c;然后负载均衡到tomcat8080和8002端口中 2 准备工作&#xff1a; 1&#xff09;准备两台tomcat容器&#xff0c;一台8080&#xff0c;一台8081 2&#xff09;在两台tomcat里面的webapps目录…

Eclipse iceoryx(千字自传)

1 在固定时间内实现无任何限制的数据传输 在汽车automotive、机器人robotics和游戏gaming等领域,必须在系统的不同部分之间传输大量数据。使用Linux等操作系统时,必须使用进程间通信(IPC)机制传输数据。Eclipse iceoryx是一种中间件,它使用零拷贝Zero-Copy、共享内存Share…

【轻松玩转MacOS】网络连接篇

引言 本篇让我们来聊聊网络连接。不论你是在家、在办公室&#xff0c;还是咖啡厅、机场&#xff0c;几乎所有的MacOS用户都需要连接到互联网。在这个部分&#xff0c;我们将向你展示如何连接到互联网和局域网。让我们开始吧&#xff01; 一、连接到互联网 首先&#xff0c;我…

http协议总结

一、http协议。 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种在Web中广泛使用的应用层协议&#xff0c;它定义了客户端和服务器之间的通信规则&#xff0c;简化了Web应用程序的开发和交互过程。其实传输是由TCP协议完成的。 HT…

UOS通过GPG对文件签名验签

本人用的版本&#xff1a;gpg (GnuPG) 2.2.12 生成密钥 生成公钥/私钥对 gpg --full-generate-key设置密钥的长度 默认回车3072&#xff0c;越长越安全。 设定密钥的有效期限 默认回车“0” 构建用户标识 输入姓名、邮件、注释后&#xff0c;输入“o”确认 在弹出框内…

vue3学习(一)---新特性

文章目录 vue3和vue2的区别重写双向数据绑定优化Vdom性能瓶颈patch flag 优化静态树 FragmentTree shaking组合式API写法 vue3和vue2的区别 重写双向数据绑定 vue2 基于Object.defineProperty()实现vue3 基于Proxy proxy与Object.defineProperty(obj, prop, desc)方式相比有以…

OpenCV级联分类器识别车辆实践笔记

1. OpenCV 级联分类器的基本原理 基于Haar特征的级联分类器的目标检测是Paul Viola和Michael Jones在2001年的论文中提出的一种有效的目标检测方法。这是一种基于机器学习的方法&#xff0c;从大量的正面和负面图像中训练级联函数。然后用它来检测其他图像中的物体。 Haar特征…