java 数据结构 优先级队列(PriorityQueue)

news2024/11/18 6:44:03

目录

优先级队列

堆的概念

堆的性质

堆的存储方式

堆的创建

堆的插入

堆的删除

用堆模拟实现优先级队列

PriorityQueue的特性

PriorityQueue常用接口介绍

堆排序


优先级队列

前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优


先级,一般出队 列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,


比如:在手机上玩游戏的时候,如 果有来电,那么系统应该优先处理打进来的电话;初中那会班


主任排座位时可能会让成绩好的同学先挑座位。


在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新


的对象这种数据结构就是优先级队列(Priority Queue)。


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


堆的概念

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储

方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i

= 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫

做最小堆或小根堆


堆的性质

1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一棵完全二叉树


堆的存储方式

从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储

注意:对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。

将元素存储到数组中后,可以根据二叉树章节的性质5对树进行还原。假设i为节点在数组中的下标,则有:

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

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

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


堆的创建

图解

代码例子:

public void shiftDown(int[] array, int parent) {
// child先标记parent的左孩子,因为parent可能右左没有右
    int child = 2 * parent + 1;
    int size = array.length;
while (child < size) {
// 如果右孩子存在,找到左右孩子中较小的孩子,用child进行标记
    if(child+1 < size && array[child+1] < array[child]){
    child += 1;
}
// 如果双亲比其最小的孩子还小,说明该结构已经满足堆的特性了
    if (array[parent] <= array[child]) {
    break;
    }else{
// 将双亲与较小的孩子交换
    int t = array[parent];
    array[parent] = array[child];
    array[child] = t;
// parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整
    parent = child;
    child = parent * 2 + 1;
}
}
}

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


堆的插入

堆的插入总共需要两个步骤:

1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)

2. 将最后新插入的节点向上调整,直到满足堆的性质

做法:

public void shiftUp(int child) {
// 找到child的双亲
    int parent = (child - 1) / 2;
while (child > 0) {
// 如果双亲比孩子大,parent满足堆的性质,调整结束
    if (array[parent] > array[child]) {
    break;
}
    else{
// 将双亲与孩子节点进行交换
    int t = array[parent];
    array[parent] = array[child];
    array[child] = t;
// 小的元素向下移动,可能到值子树不满足对的性质,因此需要继续向上调增
    child = parent;
    parent = (child - 1) / 1;
}
}
}


堆的删除

注意:堆的删除一定删除的是堆顶元素。具体如下:

1. 将堆顶元素对堆中最后一个元素交换

2. 将堆中有效数据个数减少一个

3. 对堆顶元素进行向下调整

做法:

//删除
    public int poll(int index) {
        if (empty()) {
            return -1;
        }
        int oldVal = elem[index];
        //先把要删除的元素的下标跟最后一个下标元素进行交换
        swap(index, usdSize - 1);
        //然后长度--
        usdSize--;
        //然后向下调整
        siftDown(index, usdSize);
        return oldVal;
    }


用堆模拟实现优先级队列

做法:

public 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(0);
    return oldValue;
}
public int peek() {
    return array[0];
}
}


PriorityQueue的特性

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,

PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的

关于PriorityQueue的使用要注意:


1. 使用时必须导入PriorityQueue所在的包,即:

import java.util.PriorityQueue;

2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出
ClassCastException异常

3. 不能插入null对象,否则会抛出NullPointerException

4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容

5. 插入和删除元素的时间复杂度为

6. PriorityQueue底层使用了堆数据结构

7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素


PriorityQueue常用接口介绍

1. 优先级队列的构造

代码例子:

static void TestPriorityQueue(){
// 创建一个空的优先级队列,底层默认容量是11
PriorityQueue<Integer> q1 = new PriorityQueue<>();
// 创建一个空的优先级队列,底层的容量为initialCapacity
PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
    ArrayList<Integer> list = new ArrayList<>();
    list.add(4);
    list.add(3);
    list.add(2);
    list.add(1);
// 用ArrayList对象来构造一个优先级队列的对象
// q3中已经包含了三个元素
PriorityQueue<Integer> q3 = new PriorityQueue<>(list);
    System.out.println(q3.size());
    System.out.println(q3.peek());
}
注意:默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较器

例子:

// 用户自己定义的比较器:直接实现Comparator接口,然后重写该接口中的compare方法即可
class IntCmp implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
    return o2-o1;
}
}
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> p = new PriorityQueue<>(new IntCmp());
    p.offer(4);
    p.offer(3);
    p.offer(2);
    p.offer(1);
    p.offer(5);
System.out.println(p.peek());
}
}
此时创建出来的就是一个大堆


堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

1. 建堆

升序:建大堆

降序:建小堆

2. 利用堆删除思想来进行排序

建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序

这里利用大根堆进行堆的排序

从小到大排序,我们需要建立大根堆

思路:创建大根堆,每次让下标为0的元素跟最后一个元素交换,然后调整,调整完,下标--

    //堆排序
    public void heapSort() {
        //下标最后一个的元素
        int end = usdSize - 1;
        //调整到下标为0的元素的时候结束
        while (end > 0) {
            //跟下标为0的元素进行交换
            swap(0, end);
            //向下调整
            siftDown(0, end);
            //然后倒数第二个换,以此类推
            end--;
        }
    }

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

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

相关文章

【BUG 弹药库】Tortoise git 绿色的勾 ✔ 和 红色的 !突然不见了该如何解决呢?

文章目录 1. 出现的问题描述如下所示&#xff1a;2. 如何解决这个问题呢 &#xff1f; 1. 出现的问题描述如下所示&#xff1a; 用 TortoiseGit 提交代码的时候&#xff0c;红色的 ! 和 绿色的 ✔ 突然消失了&#xff1b; 2. 如何解决这个问题呢 &#xff1f; ① 首先按住快…

新版Android Studio火烈鸟 在新建项目工程时 无法选java的语言模板解决方法

前言 最近下载最新版androidstudio时 发现不能勾选java语言模板了 如果快速点击下一步 新建项目 默认是kotlin语言模板 这可能和google主推kt语言有关 勾选1 如图所示 如果勾选 No Activity 这个模板 是可以选java语言模板的 但是里面没有默认的Activity 勾选2 和以前的用法…

SL6015B 耐压60V高调光比LED驱动IC 支持1.5A 输出30W功率

SL6015B是一款耐压60V、高调光比LED驱动IC&#xff0c;支持1.5A输出电流&#xff0c;最大输出功率达到30W。这款驱动IC专为LED照明应用而设计&#xff0c;具有出色的性能表现和广泛的应用前景。 首先&#xff0c;SL6015B的高耐压能力使其能够适用于各种高电压的LED照明场合。无…

如何免费获取基于公网 IP 的 SSL 证书 (无需域名)

现在给网站安装SSL证书来实现网站的HTTPS安全访问已经成了大多数人的共识&#xff0c;但是有一些特殊情况&#xff1a;比如对于个别的应用IP地址不需要绑定域名&#xff0c;只是单纯用IP来访问网站&#xff0c;这种情况下&#xff0c;可以实现HTTPS访问吗&#xff1f; 先说答案…

python基础——列表【创建,下标索引,常见操作方法】

&#x1f4dd;前言&#xff1a; 这篇文章主要讲解一下python中常见的数据容器之一——列表 本文主要讲解列表的创建以及我们常用的列表操作方法 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;C语言入门基础以及python入门基础 &#x1f380…

第十四届蓝桥杯省赛真题 Java 研究生 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 特殊日期试题 B: 与或异或试题 C: 棋盘试题 D: 子矩阵试题 E : \mathrm{E}: E: 互质数的个数试题 F: 小蓝的旅行计划试题 G: 奇怪的数试题 H: 太阳试题 I: 高塔试题 J \mathrm{J} J : 反异或 01 串 发现宝藏 前些天发现了一个巨牛的人…

【UE5】非持枪状态蹲姿移动的动画混合空间

项目资源文末百度网盘自取 在BlendSpace文件夹中单击右键选择动画(Animation)中的混合空间(Blend Space) &#xff0c;选择SK_Female_Skeleton&#xff0c;命名为BS_NormalCrouch 打开BS_NormalCrouch 水平轴表示角色的方向&#xff0c;命名为Direction&#xff0c;方向的最…

Java毕业设计-基于springboot开发的“智慧食堂”设计与实现-毕业论文+答辩PPT(附源代码+演示视频)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1.开发说明2.需求分析3、系统功能结构 三、系统实现展示1、系统登录2、系统功能模块3、管理员功能模块 四、毕设内容和源代码获取总结 Java毕业设计-基于springboot开发的“智慧食堂”设计与…

AI预测福彩3D第8弹【2024年3月13日预测--新算法重新开始计算第四次测试】

今天&#xff0c;先告诉大家一个好消息&#xff0c;经过修正后的算法&#xff0c;经过昨天第3次预测&#xff0c;成功命中了7码。 昨天的开奖结果是 3 7 7&#xff0c;我的预测结果均是前7码命中&#xff0c;当然&#xff0c;前6码也命中了。如果再配合缩水软件的话&#xff0c…

基于Python的中医药知识问答系统设计与实现

[简介] 这篇文章主要介绍了基于Python的中医药知识问答系统的设计与实现。该系统利用Python编程语言&#xff0c;结合中医药领域的知识和技术&#xff0c;实现了一个功能强大的问答系统。文章首先介绍了中医药知识的特点和传统问答系统的局限性&#xff0c;然后提出了设计思路…

手把手教你使用Python第三方模块

1.第三方模块 一般是别人解决特定问题的功能进行了封装&#xff0c;可以通过安装直接使用 注意 第三方模块需要先安装&#xff0c;才能使用 常见的安装方式&#xff1a;通过pip工具或者通过pycharm编辑器进行安装 2.pip指令安装 pip -V # 查看pip的版本 pip 23.2.1 fr…

深度解析:cache的基本概念原理扫盲

引流关键词:缓存,高速缓存,cache, CCI,CMN,CCI-550,CCI-500,DSU,SCU,L1,L2,L3,system cache, Non-cacheable,Cacheable, non-shareable,inner-shareable,outer-shareable, optee、ATF、TF-A、Trustzone、optee3.14、MMU、VMSA、cache、TLB、arm、armv8、armv9、TEE、安全、内存…

Palworld幻兽帕鲁管理员操作手册

Palworld幻兽帕鲁管理员操作手册 大家好我是艾西&#xff0c;在我们搭建完幻兽帕鲁服务器后肯定会涉及到后期的维护比如&#xff1a;角色修改&#xff0c;帕鲁修改&#xff0c;异常删除&#xff0c;公会修改&#xff0c;清理玩家&#xff0c;清理建筑&#xff0c;存档迁移等数…

2024自动化测试的痛点与发展趋势!

前几天在技术交流群里&#xff0c;大家讨论了很多关于自动化测试落地面临的痛点和如何创造价值的话题&#xff0c;颇有感触。 自动化测试这个话题&#xff0c;从出现到在国内大规模开展实践&#xff0c;有很长的一段时间了。早期&#xff0c;大家对自动化测试的理解和使用目的…

企业微信如何接入第三方应用?

1.登录企业微信管理后台&#xff1a;https://work.weixin.qq.com/wework_admin​​​​​ 2.点击创建应用&#xff1b; ​​​​​​​ 3. 此时可以看到已经创建好的应用&#xff0c;并且生成应用的唯一id&#xff08;agentId&#xff09; 4. 第三方应用申请域名 (举例&…

Vue3 + antv/x6 实现流程图

新建流程图 // AddDag.vue <template><div class"content-main"><div class"tool-container"><div click"undo" class"command" title"后退"><Icon icon"ant-design:undo-outlined" /…

kibana新增查看更新删除es中的数据

登录kibana&#xff0c;打开开发工具 写入数据 PUT test20240311/person/1 {"name": "张三","mobile":"13011111111" } 查询数据 GET /test20240311/person/_search {"query": {"term": {"mobile": {…

类和对象练习题

第1题 import java.util.Scanner; public class Homework01{public static void main(String[] args){//创建一个double类型的数组double array[]new double[6];//创建一个输入对象Scanner inputnew Scanner(System.in);//提示信息&#xff1a;对数组元素进行赋值System.out.pr…

docker-swarm集群管理命令

为什么选择swarm集群&#xff1f; 灵魂疑问&#xff1a;同样是集群&#xff0c;为什么选择docker swarm&#xff0c;而不不选择k8s或者k3s&#xff1f; 我的需求场景&#xff1a;不想直接用docker或者java -jar直接跑&#xff0c;修改前是使用java -jar方式&#xff0c;这两种…

爬虫练习:获取某网站的房价信息

一、相关网站 二、相关代码 import requests from lxml import etree import csv with open(房天下数据.csv, w, newline, encodingutf-8) as csvfile:fieldnames [名称, 地点,价格,总价,联系电话]writer csv.DictWriter(csvfile, fieldnamesfieldnames)writer.writeheader…