Java中的优先级队列(PriorityQueue)(如果想知道Java中有关优先级队列的知识点,那么只看这一篇就足够了!)

news2024/9/25 17:17:41

        前言:优先级队列(Priority Queue)是一种抽象数据类型,其中每个元素都关联有一个优先级,元素按照优先级顺序进行处理。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

先让我们看一下本文大致的讲解内容:

目录

1.优先队列的初识

        (1)优先级队列的定义

        (2)PriorityQueue的特性

2.优先级队列的模拟实现

3.优先级队列中常用API

        (1)创建优先级队列

        (2)插入/删除/获取优先级最高的元素/获取个数/清空/判断是否为空

4.优先级队列的使用

1. 任务调度

2. 事件驱动模拟

3. 图算法

4. 数据流处理


1.优先队列的初识

        (1)优先级队列的定义

        在开始学习Java中优先级队列的使用之前,先让我们了解一下什么是Java中的优先级队列(PriorityQueue):

        优先级队列(Priority Queue)是一种抽象数据类型,其中每个元素都关联有一个优先级,元素按照优先级顺序进行处理。与标准队列不同,优先级队列中的元素处理顺序并非按插入顺序,而是按照优先级高低来决定。

        如果读者看了优先级队列的定义之后还是不是太理解什么是优先级队列,那么现在我们使用一个日常生活中的例子来帮助你理解:

        ——例如在医院急诊室,虽然你可能先到,但是医生会根据病人的病情严重程度来决定治疗顺序。病情严重的病人(例如,心脏病发作的病人)会被优先治疗,而病情较轻的病人(例如,轻微的感冒)会被安排在后面。

        这样我相信读者就对优先级队列有了初步的认识了!!!

        (2)PriorityQueue的特性

        Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队,而对于PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,而本文我们主要介绍是PriorityQueue。

其在Java集合框架中的关系图为:

关于PriorityQueue的使用要注意:

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

import java.util.PriorityQueue;

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

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

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

        5. 插入和删除元素的时间复杂度为O(logN);

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

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

        至此,我们通过上述对Java中的优先级队列的简单讲述,我们就大致的了解了什么是Java中的优先级队列了!

2.优先级队列的模拟实现

        在了解完了什么是Java中的优先级队列之后,现在让我们想想看如何去自我实现一个Java中的优先级队列呢?

——这里我们已经在每处加上了注释,希望读者可以跟随着注释进行理解代码:

package Demo1;

import java.util.Arrays;

// 堆的自我实现 - 创建堆 + 插入数据 + 删除数据 + 返回堆顶元素 + 判断是否为空
public class MyPriorityQueue {
    public int[] elem; // 存储堆元素的数组
    public int useSize; // 当前堆中元素的个数

    // 初始化堆
    public MyPriorityQueue(int[] array) {
        elem = new int[11]; // 初始化堆的容量
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i]; // 将传入的数组元素放入堆中
            useSize++; // 更新堆中元素的个数
        }
        makeBigHeap(array, useSize); // 创建大根堆
    }

    // 整体创建堆
    public void makeBigHeap(int[] array, int useSize) {
        // 从最后一个非叶子节点开始向上调整
        for (int parent = (useSize - 1 - 1) / 2; parent >= 0; parent--) {
            shiftDown(parent, useSize); // 对每个非叶子节点进行下沉操作
        }
    }

    // 下沉操作
    private void shiftDown(int root, int useSize) {
        int child = 2 * root + 1; // 左子节点索引
        while (child < useSize) { // 遍历堆
            // 如果右子节点存在且右子节点的值大于左子节点的值,选择右子节点
            if (child + 1 < useSize && elem[child] < elem[child + 1]) {
                child++;
            }
            // 如果当前节点的值小于子节点的值,交换它们
            if (elem[root] < elem[child]) {
                swap(root, child);
                root = child; // 更新根节点为被交换的子节点
                child = 2 * root + 1; // 更新左子节点的索引
            } else {
                break; // 如果根节点的值不小于任何子节点,退出循环
            }
        }
    }

    // 在堆中插入元素
    private boolean isFull() {
        return useSize == elem.length; // 判断堆是否满了
    }

    public void offer(int val) {
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length); // 扩容
        }
        elem[useSize] = val; // 将新元素放入堆的末尾
        shiftUp(useSize); // 上浮操作调整堆
        useSize++; // 更新堆中元素的个数
    }

    // 上浮操作
    private void shiftUp(int child) {
        int parent = (child - 1) / 2; // 计算父节点的索引
        while (parent >= 0) {
            // 如果当前节点的值大于父节点的值,交换它们
            if (elem[parent] < elem[child]) {
                swap(parent, child);
                child = parent; // 更新子节点为被交换的父节点
                parent = (child - 1) / 2; // 更新父节点的索引
            } else {
                break; // 如果当前节点的值不大于父节点的值,退出循环
            }
        }
    }

    // 删除堆中元素
    public void poll() {
        if (isEmpty()) {
            throw new RuntimeException("堆中元素为空!"); // 如果堆为空,抛出异常
        }
        swap(0, useSize - 1); // 将堆顶元素与最后一个元素交换
        useSize--; // 更新堆中元素的个数
        shiftDown(0, useSize); // 对堆顶元素进行下沉操作
    }

    // 获取堆顶元素
    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("堆中元素为空!"); // 如果堆为空,抛出异常
        }
        return elem[0]; // 返回堆顶元素
    }

    // 判断堆是否为空
    private boolean isEmpty() {
        return useSize == 0; // 如果堆中没有元素,返回 true
    }

    // 交换数组中的两个元素
    private void swap(int pos1, int pos2) {
        int temp = elem[pos1];
        elem[pos1] = elem[pos2];
        elem[pos2] = temp;
    }
}
public class Test {
    public static void main(String[] args) {
        // 初始化一个整数数组
        int[] array = {1, 4, 2, 7, 9, 10, 5, 6, 8, 3};
        
        // 创建一个优先级队列实例
        MyPriorityQueue myPriorityQueue = new MyPriorityQueue(array);
        
        // 向优先级队列中插入多个元素
        myPriorityQueue.offer(5);
        myPriorityQueue.offer(3);
        myPriorityQueue.offer(8);
        myPriorityQueue.offer(1);

        // 打印堆顶元素
        System.out.println(myPriorityQueue.peek());

        // 删除堆顶元素
        myPriorityQueue.poll();
        
        // 判断堆是否为空,并打印结果(注意这里原代码并未打印结果,需手动添加打印语句)
        System.out.println("堆是否为空: " + myPriorityQueue.isEmpty());
    }
}

        从中我们可以看到我们使用堆这个数据结果来自我实现了从 - 创建堆 - 插入数据 - 删除数据 - 返回堆顶元素 - 判断是否为空等优先队列中的操作。至此我们完成了自我实现Java中的优先级队列(PriorityQueue)。

如果对于堆这种数据结构不了解的读者,可以阅读---------->Java中的Heap(堆)(如果想知道Java中有关堆的知识点,那么只看这一篇就足够了!)-CSDN博客

3.优先级队列中常用API

        通过上面的学习,我们已经了解了什么是Java中的优先级队列,并且自我实现了优先级队列,现在让我们看看Java中内置的优先级队列该如何使用吧!

        (1)创建优先级队列

PriorityQueue类提供了多种构造方法,允许创建不同配置的优先级队列。

构造器功能
PriorityQueue()创建一个空的优先级队列,默认容量是11
PriorityQueue(int initialCapacity)创建一个初始容量为initialCapacity的优先级队列,注意:
initialCapacity不能小于1,否则IllegalArgumentException异常
PriorityQueue(Collection<? extends E> c)

用一个集合来创建优先级队列

例子:

import java.util.PriorityQueue;

public class PriorityQueueDemo {
    public static void main(String[] args) {
        // 默认初始容量的优先级队列
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        
        // 指定初始容量的优先级队列
        PriorityQueue<Integer> pqWithCapacity = new PriorityQueue<>(20);
        
        // 使用比较器的优先级队列
        PriorityQueue<Integer> pqWithComparator = new PriorityQueue<>(new CustomComparator());
    }
}

        ——这样我们就会常见Java中的优先级队列了!

在了解了如何创建一个优先级队列之后,接下来让我们看一下如何去操作这个创建的优先级队列。

        (2)插入/删除/获取优先级最高的元素/获取个数/清空/判断是否为空

函数名功能
boolean offer(E e)插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度O(logN),注意:空间不够时候会进行扩容
E peek()获取优先级最高的元素,如果优先级队列为空,返回null
E poll()移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size()获取有效元素的个数
void clear()清空
boolean isEmpty()检测优先级队列是否为空,空返回true

例子:

import java.util.PriorityQueue;

public class Test {
    public static void main(String[] args) {
        // 初始化一个整数数组
        int[] arr = {4, 1, 9, 2, 8, 0, 7, 3, 6, 5};

        PriorityQueue<Integer> q = new PriorityQueue<>(arr.length);
        
        // 将数组中的元素添加到优先级队列中
        for (int e : arr) {
            q.offer(e);
        }
        
        // 打印优先级队列中有效元素的个数
        System.out.println(q.size());
        
        // 获取并打印优先级队列中优先级最高的元素(即最小值,因为是最小堆)
        System.out.println(q.peek());
        
        // 从优先级队列中删除两个元素
        q.poll();
        q.poll();
        
        // 打印删除两个元素后,优先级队列中有效元素的个数
        System.out.println(q.size());
        
        // 获取并打印当前优先级最高的元素
        System.out.println(q.peek());
        
        // 向优先级队列中插入一个新的元素
        q.offer(0);
        
        // 获取并打印插入新元素后的优先级最高的元素
        System.out.println(q.peek());
        
        // 清空优先级队列中的所有有效元素
        q.clear();
        
        // 检测优先级队列是否为空,并打印结果
        if (q.isEmpty()) {
            System.out.println("优先级队列已经为空!!!");
        } else {
            System.out.println("优先级队列不为空");
        }
    }
}

        ——这样我们就大致的了解了如何操作Java中的优先级队列了!!!

4.优先级队列的使用

        优先级队列(Priority Queue)是一种特殊的数据结构,用于处理具有优先级的元素。它的主要特点是能够高效地插入元素并以优先级顺序访问和删除元素。以下是优先级队列的一些主要应用场景:

1. 任务调度

  • 场景: 操作系统和调度系统常常需要管理多个任务,每个任务具有不同的优先级。

  • 用法: 优先级队列可以用来实现任务调度系统,其中优先级高的任务会被优先执行。比如,操作系统的进程调度器会使用优先级队列来决定哪个进程应该优先获得 CPU 时间。

2. 事件驱动模拟

  • 场景: 在模拟系统(如网络仿真或离散事件模拟)中,事件会在未来的某个时间点发生。

  • 用法: 优先级队列用于存储和处理这些事件,确保在模拟中按事件的发生时间顺序处理它们。

3. 图算法

  • 场景: 在计算图的最短路径(如 Dijkstra 算法)或最小生成树(如 Prim 算法)时,需要按边的权重或节点的距离进行操作。

  • 用法: 使用优先级队列可以有效地管理和访问图中的边或节点,以支持这些算法的高效执行。

4. 数据流处理

  • 场景: 数据流中的数据可能具有不同的重要性或优先级。

  • 用法: 在处理实时数据流时,优先级队列可以用来根据数据的优先级顺序处理数据。

这样我们就大致的了解了Java中的优先级队列在日常中的使用地方了!


以上就是本篇文章的全部内容了~~~

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

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

相关文章

从零开始之AI视频制作篇

从零开始之AI视频制作篇 文章目录 从零开始之AI视频制作篇前言一、工具列表二、成片展示三、制作流程1、获取图片素材2、图片生成视频2.1 Runway操作流程 3、文本生成语音3.1 Fish Audio操作流程 4、视频剪辑4.1 音频素材4.2 字幕生成 四、Runway提示词参考&#xff1a;参考 前…

盘点5个PDF 怎么转换成 Word 的实用技巧

在日常的办公和学习中&#xff0c;要将 PDF 文件转换成 Word 是很常有的事。方便我们编辑、修改内容或者是提取其中的内容。一般都会用到一些工具&#xff1b;下面&#xff0c;我将为大家介绍5种高效且实用的 PDF 转 Word 的方法。 1、PDF365转换软件 直通车&#xff1a;www.…

搜维尔科技:【研究】大屏幕沉浸式系统的优势,视觉冲击强、‌分辨率高、‌画面层次感强以及沉浸式交互性体验好等!

大屏幕沉浸式系统的优势主要体现在视觉冲击强、‌分辨率高、‌画面层次感强以及沉浸式交互性体验好。‌ 视觉冲击强&#xff1a;‌大屏幕沉浸式系统通过使用多台投影机投射画面&#xff0c;‌结合高质量影片&#xff0c;‌营造出场景环境&#xff0c;‌通过视觉艺术直击体验者…

Hanoi(汉诺)塔问题

目录 什么是汉诺塔&#xff1f; 如何分析汉诺塔 代码实现汉诺塔 什么是汉诺塔&#xff1f; 这是一个古典的数学问题&#xff0c;是一个用递归方法解题的典型例子。汉诺塔的故事在这里不做介绍啦&#xff01; 汉诺塔的思想是&#xff1a; 总共有3根柱子&#xff0c;这里假设为…

书生.浦江大模型实战训练营——(三)Git基本操作与分支管理

最近在学习书生.浦江大模型实战训练营&#xff0c;所有课程都免费&#xff0c;以关卡的形式学习&#xff0c;也比较有意思&#xff0c;提供免费的算力实战&#xff0c;真的很不错&#xff08;无广&#xff09;&#xff01;欢迎大家一起学习&#xff0c;打开LLM探索大门&#xf…

趋动科技荣登「AIGC赋能金融创新引领者TOP20」

2023年11月28日&#xff0c;“极新AIGC行业峰会”在北京召开&#xff0c;峰会以“AI落地”为指引&#xff0c;探究AI实践与产业化。 从制造业到金融服务业&#xff0c;从医疗保健到交通运输&#xff0c;从文化娱乐到消费零售&#xff0c;智能客服、数字人直播、智能巡检机器人&…

RocketMQ5.0课笔记-架构设计

rocketmq云原生架构 rocketmq的可观测性 NameServer服务发现和注册 rocketMQ的负载均衡 rocketmq高可用方案设计

pod的存储卷

容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重启它&#xff0c;但是容器中的文件将丢失——容器以干净的状态&#xff08;镜像最初的状态&#xff09;重新启动。其次&a…

【轨物洞见】光伏电站组件满发小时偏差监测分析方案

光伏发电作为一种环保、可再生的能源形式&#xff0c;在全球得到了广泛的应用。然而&#xff0c;与其他发电方式相比&#xff0c;光伏发电的产能与天气条件息息相关。长期以来&#xff0c;人们一直关注光伏满发小时偏差的问题&#xff0c;并不断努力找到解决方案。 光伏满发小时…

C++笔记1•C++入门基础•

1.C关键字 C总计63个关键字&#xff0c;C语言32个关键字&#xff1a; 2.命名空间&#xff1a; 在 C/C 中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目…

VSCode学习记录

一、下载相关包 npm install npm install vue-router //路由 npm install axios npm install element-plus --save //组件 二、构建一个简单的项目 1.创建router文件夹&#xff0c;在里面创建一个index.js文件用来管理不同页面的路由 import {createRouter,createWebHashHist…

【virtuoso】ocean脚本生成数据文件

1. 生成的原始脚本文件 点击ADE&#xff0c;Sessionsave Ocean Script (如果是AED Explorer或者 ADE Assembler)点击之后会出现这样选项 第2个选项&#xff0c;保存东西更多。这里选择第一个选项 输出的脚本如图所示 ocean文件 1simulator仿真器选择2design设计文件所在位置3r…

循环依赖问题和Spring三级缓存

产生原因&#xff1a;两个或多个bean之间互相持有对方的引用 解决&#xff1a;spring三级缓存 一级缓存&#xff1a;单例池&#xff0c;存放已经经历了完整的生命周期的bean 二级缓存&#xff1a;存放早期的&#xff0c;还没走完生命周期的bean 三级缓存&#xff1a;存放对…

Linux编译器 gcc/g++使用

目录 0.前言 1.C/C编译链接过程回顾 2.gcc如何完成编译链接 2.1预处理 2.2编译 2.3汇编 2.4链接 3.gcc编译选项 4.函数库 4.1静态库 4.2动态库 5.小结 &#xff08;图像由AI生成&#xff09; 0.前言 在Linux系统中&#xff0c;C/C编程的开发工具不可或缺&#xff0c;其中gcc…

写给非机器学习人员的 embedding 入门

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

合并两个有序数组(LeetCode)

题目 给你两个按 非递减顺序 排列的整数数组 和 &#xff0c;另有两个整数 和 &#xff0c;分别表示 和 中的元素数目。请你 合并 到 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff1a;最终&#xff0c;合并后数组不应由函数返回&#xff0c;而是…

Word中加载Mathtype后粘贴复制快捷键(Ctrl+C/V)不能使用

操作环境 windows 11操作系统 word版本2021 mathtype版本7.4 这个问题只出现在word中&#xff0c;在excel和ppt中都不存在这个问题&#xff0c;而且之前在另一台电脑中使用word2016版本并没有这种问题的&#xff0c;然后网上搜了一下有不少人有这种问题&#xff0c;word直接取…

nodejs/node-sass/sass-loader三者版本对应关系(已解决)

基本前提&#xff1a;了解版本对应关系 示例&#xff1a; 我的nodejs&#xff1a;v14.21.3&#xff0c; 则package.json: "node-sass": "^4.14.1", "sass-loader": "^8.0.0",扩展&#xff1a; 查看node历史版本&#xff1a; Node.js…

【数据结构-前缀哈希】力扣525. 连续数组

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组&#xff0c;并返回该子数组的长度。 示例 1: 输入: nums [0,1] 输出: 2 说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。 示例 2: 输入: nums [0,1,0] 输出: 2 说明: [0, 1] (或 [1, 0]) 是…

摸着石头过河的具身智能公司,正在寻求“确定性”

在种种不确定因素之下&#xff0c;对于具身智能&#xff0c;唯一可以确定的是&#xff0c;其未来巨大的市场空间。从纷纷入局的科技巨头、创业公司的市场现状即可窥见一二。而类比到自动驾驶&#xff0c;其也是抛开层层迷雾后才得以在今天看见曙光。 相信&#xff0c;于具身智…