算法与数据结构(七):优先队列

2023-11-16

  • 博主会对算法与数据结构会不断进行更新,敬请期待,如有什么建议,欢迎联系。
  • 我们知道队列具有先进先出的特性,栈具有先进后出的特性,那么有没有一种数据结构可以根据自己的需求,以一定的规则从队列中弹出呢,优先队列就是实现这种目标的数据结构。一般情况下,计算机的任务都是有优先级的,我们需要从所有任务中找到优先级最高的任务优先执行,执行完毕后把这个任务从队列中移除。普通的队列需要完成这种要求,需要每次从队列中遍历所有元素找出最大值,效率不是很高,这个时候我们就可以采用一种数据结构来完成这种需求,那就是优先队列。在这里详细介绍了最大优先队列和最小优先队列以及他们的简单实现。
  • 最大优先队列和最小优先队列每次弹出都是队列中的最大值或最小值,但是他们有一个缺点没有办法通过索引访问已存在优先队列中的索引对象,并更新他们,因此索引优先队列呼之欲出。索引优先队列可以更新队列中的任何一个元素,并通过下沉或上浮算法重新调整元素在队列中的顺序。

优先队列的实现细节:

  • 优先队列是建立在堆的数据基础之上的;
  • 最大优先队列头节点为最大值,在弹出最大值之前将头结点与尾结点进行交换,弹出最大值,然后再对头结点进行下沉操作;
  • 最小优先队列头节点为最小值,在弹出最小值之前将头节点与尾结点进行交换,弹出最小值,然后再堆头节点进行下沉操作;
  • 相对于最大、最小优先队列,索引优先队列成员变量中有三个数组,一个是用来储存元素的数组items,一个是保存每个元素在items数组中的索引,进行堆排序的数组queue,最后一个是保存queue的逆序,queue的值作为索引,queue的索引作为值的reverseQueue
  • 最大优先队列的实现代码如下:

package com.victor.heap;

/**
 * @description:
 * @author: victor
 */
public class MaxPriorityQueue<T extends Comparable<T>> {

    //存储堆中的元素
    private T[] items;
    //元素个数
    private int N;

    @SuppressWarnings("unchecked")
    public MaxPriorityQueue(int capacity) {
        this.items = (T[]) new Comparable[capacity + 1];
        N = 0;
    }

    public MaxPriorityQueue(){
        this(16);
    }


    public int size() {
        return N;
    }

    public boolean isEmpty() {
        return N == 0;
    }

    private boolean less(int i, int j) {
        return items[i].compareTo(items[j]) < 0;
    }


    private void exchange(int i, int j) {
        T temp = items[i];
        items[i] = items[j];
        items[j] = temp;
    }

    public void insert(T t) {
        items[++N] = t;
        swim(N);
    }

    /**
     * 删除最大值
     *
     * @return 最大值
     */
    public T deleteMax() {
        T max = items[1];
        exchange(1, N);
        N--;
        sink(1);
        return max;
    }

    /**
     * 下沉算法
     *
     * @param k 下沉的小标
     */
    private void sink(int k) {
        while (2 * k <= N) {
            int max = 2 * k;
            int right = max + 1;
            if (right <= N)
                max = less(max, right) ? right : max;
            if (less(k, max))
                exchange(k, max);
            else
                break;
            k = max;
        }
    }

    /**
     * 上浮算法
     *
     * @param k 上浮的下标
     */
    private void swim(int k) {
        while (k > 1) {
            if (less(k / 2, k))
                exchange(k / 2, k);
            else
                break;
            k = k / 2;
        }
    }
}

  • 最小优先队列的实现代码如下:
package com.victor.heap;

/**
 * @description:
 * @author: victor
 */
public class MinPriorityQueue<T extends Comparable<T>> {

    private T[] items;
    private int N;
    @SuppressWarnings("unchecked")
    public MinPriorityQueue(int capacity) {
        this.items = (T[]) new Comparable[capacity + 1];
        N = 0;
    }

    public MinPriorityQueue() {
        this(16);
    }

    public boolean isEmpty() {
        return N == 0;
    }

    private boolean less(int i, int j) {
        return items[i].compareTo(items[j]) < 0;
    }

    private void exchange(int i, int j) {
        T temp = items[i];
        items[i] = items[j];
        items[j] = temp;
    }

    public void insert(T t) {
        items[++N] = t;
        swim(N);
    }

    public T deleteMin() {
        T min = items[1];
        exchange(1, N);
        N--;
        sink(1);
        return min;
    }


    private void swim(int k) {
        while (k > 1) {
            if (less(k, k / 2))
                exchange(k, k / 2);
            else
                break;
            k = k / 2;
        }
    }

    private void sink(int k) {
        while (2 * k <= N) {
            int min = 2 * k;
            int right = min + 1;
            if (right <= N)
                min = less(min, right) ? min : right;
            if (less(min, k))
                exchange(min, k);
            else
                break;
            k = min;
        }
    }

}

  • 最大优先队列与最小优先队列还是比较简单的,基本与堆的实现类似,插入进行上浮算法,删除进行下沉算法。
package com.victor.heap;

import java.util.Arrays;

/**
 * 索引优先队列
 *
 * @description: 下标最小优先队列
 * @author: victor
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class IndexMinPriorityQueue<T extends Comparable> {
    /*用来储存元素的数组*/
    private T[] items;
    /*保存每个元素在items数组中的索引,进行堆排序的数组*/
    private int[] queue;
    /*保存queue的逆序,queue的值作为索引,queue的索引作为值*/
    private int[] reverseQueue;
    /*数组元素的个数*/
    private int N;

    public IndexMinPriorityQueue(int capacity) {
        this.items = (T[]) new Comparable[capacity + 1];
        this.queue = new int[capacity + 1];
        this.reverseQueue = new int[capacity + 1];
        //将reverseQueue的每个元素设置为-1
        Arrays.fill(reverseQueue, -1);
    }


    /**
     * 判断是否小于
     *
     * @param i queue的索引
     * @param j queue的索引
     * @return 是否i小于j
     */
    private boolean less(int i, int j) {
        return items[queue[i]].compareTo(items[queue[j]]) < 0;
    }

    /**
     * 数组queue交换索引i,j
     *
     * @param i queue数组的索引i
     * @param j queue数组的索引j
     */
    private void exchange(int i, int j) {
        int temp = queue[i];
        queue[i] = queue[j];
        queue[j] = temp;
        //更新reverseQueue中的数据
        reverseQueue[queue[i]] = i;
        reverseQueue[queue[j]] = j;

    }

    /**
     * 删除最小元素并返回该元素的索引
     *
     * @return 最小元素的索引
     */
    public int delMin() {
        int minIndex = queue[1];
        exchange(1, N);
        items[minIndex] = null;     //将最小的值置空
        reverseQueue[queue[N]] = -1;
        queue[N] = -1;
        N--;
        sink(1);
        return minIndex;
    }

    /**
     * 往队列中插入一个元素并关联索引
     *
     * @param i 索引
     * @param t 要插入的值
     */
    public void insert(int i, T t) {
        //如果此索引位置已存在,则不能插入
        if (contains(i)) return;
        //插入
        items[i] = t;
        N++;
        //队列最后位置加入数组的索引
        queue[N] = i;
        reverseQueue[i] = N;
        swim(N);
    }

    /**
     * 上浮算法
     *
     * @param k 要上浮的索引
     */
    private void swim(int k) {
        while (k > 1) {
            if (less(k, k / 2)) exchange(k, k / 2);
            else break;
            k = k / 2;
        }
    }

    /**
     * 下沉算法
     *
     * @param k 要下沉的索引
     */
    private void sink(int k) {
        while (2 * k <= N) {
            int min = 2 * k;
            int right = min + 1;
            if (right <= N) min = less(min, right) ? min : right;
            if (less(min, k)) exchange(min, k);
            else break;
            k = min;
        }
    }

    /**
     * 队列的尺寸
     *
     * @return 队列的尺寸
     */
    public int size() {
        return N;
    }

    /**
     * 队列是否为空
     *
     * @return 是否为空
     */
    public boolean isEmpty() {
        return N == 0;
    }

    /**
     * 是否包换k
     *
     * @param k 索引k
     * @return 是否存在
     */
    public boolean contains(int k) {
        return reverseQueue[k] != -1;
    }

    /**
     * 把与索引i有关的元素修改为t
     *
     * @param i 索引i
     * @param t 要修改的元素为t
     */
    public void changeItem(int i, T t) {
        if (i >= N) {
            insert(i, t);
            return;
        }

        items[i] = t;
        int k = reverseQueue[i];
        swim(k);
        sink(k);
    }

    /**
     * 最小元素关联的索引
     *
     * @return 最小元素的索引
     */
    public int minIndex() {
        return queue[1];
    }

    /**
     * 删除索引i对应的元素
     *
     * @param i 索引i
     */
    public void delete(int i) {
        int k = reverseQueue[i];    //索引i对应的队列索引
        exchange(k, N);             //交换k处的索引与最后的索引
        items[i] = null;
        reverseQueue[queue[N]] = -1;       //必须先交换再设置为-1
        queue[N] = -1;
        N--;
        //上浮和下沉都要做,因为不知道k是比较大还是比较小,但是,上浮或下沉只会成功一个
        sink(k);
        swim(k);
    }
}

  • 索引优先队列在删除一个元素的时候,一定要先和队列最后的元素进行交换后再进行删除,此时reverseQueue中的元素也进行了交换,再删除reverseQueue中queue[N]的元素。
  • 删除之后上浮和下沉操作都要做,因为不知道交换后的元素是比较大还是比较小,但是上浮和下沉只会成功一个。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

算法与数据结构(七):优先队列 的相关文章

  • 使用 Guice 注入类集合

    我正在尝试用 Google Guice 2 0 注入东西 我有以下结构 FooAction implements Action BarAction implements Action 然后我有一个带有以下构造函数的 ActionLibrar
  • 如何在 Java 中访问嵌套的 HashMap?

    我有一个 Java 中的 HashMap 其中的内容 你们可能都知道 可以通过以下方式访问 HashMap get keyname 如果一个 HashMap 位于另一个 HashMap 中 即嵌套的 HashMap 我将如何访问内容 我可以
  • 将一种类型的对象声明为另一种类型的实例有什么好处? [复制]

    这个问题在这里已经有答案了 可能的重复 Base b2 new Child 是什么意思 表示 https stackoverflow com questions 4447924 what does base b2 new child sig
  • 单元测试组合服务方法

    我正在为一个类编写 junit 单元测试 该类使用以下方法实现公开的接口 public Set
  • 如何配置 Spring-WS 以使用 JAXB Marshaller?

    感谢您到目前为止对此的帮助 我正在更新问题 因为我没有显示我需要的所有内容 并显示了建议的更改 肥皂输出仍然不是我想要的 servlet xml
  • JavaFX 2.0 FXML 子窗口

    经过多次搜索我发现了这个问题如何创建 javafx 2 0 应用程序 MDI https stackoverflow com questions 10915388 how to create a javafx 2 0 application
  • 具有 CRUD 功能的基于 Spring Web 的管理工具

    在 PHP Symfony 世界里有一个工具叫 Sonata Adminhttps sonata project org https sonata project org 基于 AdminLTE 模板 这是一款一体化管理工具 具有登录 菜单
  • OpenNLP 与斯坦福 CoreNLP

    我一直在对这两个包进行一些比较 但不确定该往哪个方向走 我简单地寻找的是 命名实体识别 人 地点 组织等 性别识别 一个不错的训练 API 据我所知 OpenNLP 和斯坦福 CoreNLP 提供了非常相似的功能 然而 Stanford C
  • 正则表达式在 Velocity 模板中不起作用

    我在 Test java 中尝试过这个 String regex lt s br s s gt String test1 lt br gt System out println test replaceAll regex 但是当我在速度模板
  • Java - JPanel 内有边距和 JTextArea

    我想创建这样的东西 主面板有其边距 x 并且 TextArea 位于该面板的中心 几乎填满了面板 底部是另一个具有自定义尺寸 高度 y 的面板 可以使用某些快捷方式将其切换为可见和不可见 底部面板有 FlowLayout 和几个元素 问题是
  • LocalDate 减去 period 得到错误的结果

    LocalDate减去一个Period 如 28年1个月27天 得到错误的结果 但减去一个Period 只有天单位 如 10282 天 得到正确的结果 有什么需要注意的吗 public static void main String arg
  • Cucumber DataTable 错误 - io.cucumber.datatable.UndefinedDataTableTypeException:无法将 DataTable 转换为 cucumber.api.DataTable

    尝试使用 cucumber selenium java intelliJ 运行场景 但在其中一个步骤中出现有关 DataTable 的错误 在我开始使用测试运行程序并更改周围的一些内容之前 数据表工作正常并正确转换该步骤的参数 但我就是无法
  • 更改 JComboBox 中滚动条的大小

    有谁知道如何手动更改 jComboBox 中的滚动条大小 我已经尝试了一大堆东西 但没有任何效果 好吧 我明白了 您可以实现 PopUpMenuListener 并使用它 public void popupMenuWillBecomeVis
  • Android 解析 JSON 卡在 get 任务上

    我正在尝试解析一些 JSON 数据 我的代码工作了一段时间 我不确定我改变了什么突然破坏了代码 当我运行代码时 我没有收到任何运行时错误或警告 我创建一个新的 AsyncTask 并执行它 当我打电话时 get 在这个新任务中 调试器在此行
  • 多线程——更快的方法?

    我有一堂有吸气剂的课程getInt 和一个二传手setInt 在某个领域 比如说领域 Integer Int 一个类的一个对象 比如说SomeClass The setInt 这里是同步的 getInt isn t 我正在更新的值Int来自
  • JAXB 编组器无参数默认构造函数

    我想从 java 库中编组一个 java 对象 当使用 JAXB marschaller 编组 java 对象时 我遇到了一个问题 A 类没有无参数默认构造函数 我使用Java Decompiler来检查类的实现 它是这样的 public
  • Java8:流映射同一流中的两个属性

    我有课Model带有以下签名 class Model private String stringA private String stringB public Model String stringA String stringB this
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • Java 中的微分方程

    我正在尝试用java创建一个简单的SIR流行病模型模拟程序 基本上 SIR 由三个微分方程组定义 S t l t S t I t l t S t g t I t R t g t I t S 易感人群 I 感染人群 R 康复人群 l t c
  • 使用 AmazonSNSClient 发送短信时的授权

    aws 官方文档如何发送短信 http docs aws amazon com sns latest dg sms publish to phone html使用 java 中的 aws SDK 非常简单 但是 当发送如底部示例所示的消息时

随机推荐

  • SpringBoot+Vue如何写一个HelloWorld

    一 SpringBoot介绍 Spring Boot是一个用于创建独立且可执行的Spring应用程序的框架 它简化了基于Spring框架的应用程序的开发过程 并提供了一种快速和简便的方式来构建Java应用程序 Spring Boot提供了自
  • 5. 智能指针(等后续

    指针本质上是一个内存地址索引 代表了一块内存区域 能够直接读写内存 因为指针完全映射了计算机硬件 所以操作效率高 是C C 高效的根源 但是指针也会产生访问无效数据 指针越界或者内存分配不及时等导致的运行错误 内存泄漏 资源丢失等一系列问题
  • 最新Keil MDK下载安装

    百度网盘下载 Keil MDK MDK5 38a https pan baidu com s 1REHRICabWMn0gHp8bgroWQ pwd 1122 MDK5 37 https pan baidu com s 1eA5cSpvCY
  • SpringBoot微信小程序授权登录

    SpringBoot微信小程序授权登录 一 appId 1 1 自己是管理者 微信公众平台 申请或登录自己的微信小程序 在开发者管理中即可看到 2 2 自己是开发者 让管理员将自己加入到小程序开发者管理中 用管理者提供的appId和secr
  • 【Flink系列】配置管理rockmq-flink产生的rocketmq-client日志

    Flink任务集成了rockmq flink用于订阅消费rocketmq的消息 在任务运行过程中发现会在系统的 username logs rocketmqlogs目录下产生rocketmq client log日志 并且这个日志累积和滚动
  • OException parsing XML document from class path resource [beans.xml]

    项目场景 在学习spring的时候配置xml遇到了一个问题 问题描述 IOException parsing XML document from class path resource beans xml nested exception
  • 通过PAGE生成python GUI界面(用PAGE拖出需要的GUI界面)

    注 当前我的使用环境为windows10 64bit python v3 6 PAGE v4 14 Tcl v8 6 7 0 当前我定义一个目标 最终需要生成一个登录界面的GUI代码 如下 安装好各软件后 就可以运行PAGE来像VB一样所见
  • 【统一解决OpenCV+contrib编译过程中ippicv、face_landmark_model以及boostdesc/vgg_generated文件下载缓慢问题】

    统一解决OpenCV contrib编译过程中ippicv face landmark model以及boostdesc vgg generated文件下载缓慢问题 在编译过程中 ippicv face landmark model以及bo
  • python爬虫之爬取百度翻译

    使用python中requests模块就可以爬取 import requests post url https fanyi baidu com sug headers User Agent Mozilla 5 0 Windows NT 10
  • 【华为机试真题 Python】统计每个月兔子的总数

    目录 题目描述 输入 输出 示例 参考代码 题目描述 有一种兔子 从出生后第3个月起每个月都生一只兔子 小兔子长到第三个月后每个月又生一只兔子 例子 假设一只兔子第3个月出生 那么它第5个月开始会每个月生一只兔子 一月的时候有一只兔子 假如
  • 音视频简易播放器代码范例

    下面是一个简单的音视频播放器代码范例 使用Python语言和PyQt5框架 python import sys from PyQt5 QtCore import Qt QUrl from PyQt5 QtMultimedia import
  • fgets函数的理解

    fget函数的原型如下 char fgets char buf int n FILE fp 功能 从文件流读取一行 送到缓冲区 使用时注意以下几点 1 当遇到换行符或者缓冲区已满 fgets就会停止 返回读到的数据 值得注意的是不能用fge
  • javaweb (一) ——web与servlet

    文章目录 web 1 客户端和服务器 服务器软件 网络协议 虚拟主机 静态和动态内容 安全性 2 URL 3 HTML 4 CSS 5 JavaScript 6 HTTP 请求方法 请求头 请求体 响应状态码 响应头 响应体 7 Web 应
  • 【Spring Boot】Spring Boot框架

    文章目录 Spring Boot 1 概念 特点及其好多 2 springBoot的初体验 2 1 步骤 2 1 1创建项目 2 1 2 加入依赖 2 1 3 启动类 2 1 4 controller类 2 1 5 测试 3 配置文件 3
  • 高标准农田信息化管理平台概要设计

    1 综合信息一张图系统 通过一张图的形式 可视化直观展示地区土地分布 耕地质量 高标准农田建设情况 灌溉情况 设备分布情况及环境监测数据 农业管理者可在一张图上查看农田相关信息 及时了解农田情况 为农田管理者的精准管理和科学决策提供辅助支撑
  • Asp.Net&.Net Core 使用 SonarQube 踩坑记 (使用 MSBuild扫描器篇)

    使用dotnet 需要 搭建 ner core的运行环境 1 首先安装配置java运行环境 且javaJDK 必须是11以上 jdk版本必须大于11 等于11不行 2 java和java JDK后 记得配置java 和jdk建立连接和配置
  • formdata上传文件_关于multipart/formdata上传文件

    最近在做一个文件上传的开放接口 用到Content Type multipart form data这种请求类型 特地做了一些研究和记录 在最初的 http协议中 并没有上传文件方面的功能 RFC1867为 http协议添加了这个能力 常见
  • 深度学习笔试、面试题 二

    1 梯度爆炸问题是指在训练深度神经网络的时候 梯度变得过大而损失函数变为无穷 在RNN中 下面哪种方法可以较好地处理梯度爆炸问题 A 用改良的网络结构比如LSTM和GRUs B 梯度裁剪 C Dropout D 所有方法都不行 正确答案是
  • Linux-写USB键盘驱动(详解)

    1 首先我们通过上节的代码中修改 来打印下键盘驱动的数据到底是怎样的 先来回忆下 我们之前写的鼠标驱动的id table是这样 所以我们要修改id table 使这个驱动为键盘的驱动 如下图所示 然后修改中断函数 通过printk 打印数据
  • 算法与数据结构(七):优先队列

    博主会对算法与数据结构会不断进行更新 敬请期待 如有什么建议 欢迎联系 我们知道队列具有先进先出的特性 栈具有先进后出的特性 那么有没有一种数据结构可以根据自己的需求 以一定的规则从队列中弹出呢 优先队列就是实现这种目标的数据结构 一般情况