数据结构与算法——Java实现 29.优先级队列

news2024/11/27 12:48:29

事缓则圆,人缓则安

                        —— 24.10.5

一、优先级队列

优先级队列                一端进,另一端出                按优先级出队

普通队列                    一端进,另一端出                先进先出FIFO


二、无序数组实现

Type parameters:<E>:队列中元素的类型,必须实现Priority接口


思路

设置对象优先级Entry,每个存入数组的元素都有它的优先级,无序数组实现时,加入元素直接在数组尾部进行添加,删除元素时遍历一遍数组,寻找优先级最大的元素,将优先级最大的元素进行删除


对象优先级接口

public interface Priority {
    // 返回对象的优先级,约定数字越大,优先级越高
    // Returns:优先级
    int priority();
}

优先级接口实现

public class Entry implements Priority{
    String value;
    int priority;

    public Entry(String value, int priority) {
        this.value = value;
        this.priority = priority;
    }

    @Override
    public int priority() {
        return priority;
    }

    @Override
    public String toString() {
        return "Entry{" +
                "value='" + value + '\'' +
                ", priority=" + priority +
                '}';
    }
}

队列接口

public interface Queue<E> {
    /*
        向队列尾部插入值
        Params:value-待插入值
        Returns:插入成功返回true,插入失败返回false
     */
    boolean offer(E e);

    /*
        从队列头获取值,并移除
        Returns:如果队列非空返回头部值,否则返回null
     */
    E poll();

    /*
        从队列头获取值,不移除
        Returns:如果队列非空返回队头值,否则返回null
     */
    E peek();

    /*
        检查队列是否为空
        Return:空返回true,否则返回false
     */
    boolean isEmpty();

    /*
        检查队列是否为满
        Return:满返回true,否则返回false
     */
    boolean isFull();
}

无序数组实现队列接口

import Day10Queue.Queue;

import java.util.Arrays;

public class PriorityQueue1<E extends Priority> implements Queue<E> {
    // 数据类型E要实现Priority接口,所以数组类型直接定义成Priority
    Priority[] array;
    int size;

    public PriorityQueue1(int capacity) {
        array = new Priority[capacity];
    }

    // 添加元素
    @Override
    public boolean offer(E e) {
        if (isFull()) {
            return false;
        }
        array[size] = e;
        size++;
        return true;
    }

    // 寻找优先级最高的索引值
    private int selectMax(){
        int max = 0;
        for (int i = 0; i < size - 1; i++) {
            // 寻找优先级最高的元素
            if (array[i].priority() > array[max].priority()){
                max = i;
            }
        }
        return max;
    }
    
    // 删除元素
    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        int max = selectMax();
        E e = (E) array[max];
        remove(max);
        return e;
    }

    // 删除元素
    private void remove(int index) {
        if (index == size - 1) {
            array[size] = null;
        } else if (index < size-1) {
            // 原数组 原数组起始位置 目的数组 目的数组起始位置 移动的元素个数
            System.arraycopy(array,index+1,array,index,size-index-1);
        }
        size--;
        array[size] = null;
    }

    // 获取元素
    @Override
    public E peek() {
        if (isEmpty()){
            return null;
        }
        int max = selectMax();
        return (E) array[max];
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public boolean isFull() {
        return size==array.length;
    }

    @Override
    public String toString() {
        return "PriorityQueue1{" +
                "array=" + Arrays.toString(array) +
                ", size=" + size +
                '}';
    }
}

测试类

import org.junit.Test;

import static org.junit.jupiter.api.Assertions.*;

public class TestPriorityQueue1 {

    @Test
    public void poll(){
        PriorityQueue1<Entry> queue1 = new PriorityQueue1<>(5);
        queue1.offer(new Entry("task1",4));
        queue1.offer(new Entry("task2",3));
        queue1.offer(new Entry("task3",2));
        queue1.offer(new Entry("task4",5));
        queue1.offer(new Entry("task5",1));
        assertFalse(queue1.offer(new Entry("task6",7)));

        assertEquals(5, queue1.poll().priority());
        assertEquals(4, queue1.poll().priority());
        assertEquals(3, queue1.poll().priority());
        assertEquals(2, queue1.poll().priority());
        assertEquals(1, queue1.poll().priority());
        System.out.println(queue1.toString());
    }
}


三、有序数组实现

Type parameters:<E>:队列中元素的类型,必须实现Priority接口


思路

将元素按照优先级进行排序存储在基于有序数组实现的队列中,删除元素时只需要在数组最尾端进行出队操作,添加元素时需要遍历一遍队列内的元素,寻找新元素优先级存储的位置,将新元素存储在其优先级按序排列的数组中的位置


 对象优先级接口

public interface Priority {
    // 返回对象的优先级,约定数字越大,优先级越高
    // Returns:优先级
    int priority();
}

优先级接口实现

public class Entry implements Priority{
    String value;
    int priority;

    public Entry(String value, int priority) {
        this.value = value;
        this.priority = priority;
    }

    @Override
    public int priority() {
        return priority;
    }

    @Override
    public String toString() {
        return "Entry{" +
                "value='" + value + '\'' +
                ", priority=" + priority +
                '}';
    }
}

队列接口

public interface Queue<E> {
    /*
        向队列尾部插入值
        Params:value-待插入值
        Returns:插入成功返回true,插入失败返回false
     */
    boolean offer(E e);

    /*
        从队列头获取值,并移除
        Returns:如果队列非空返回头部值,否则返回null
     */
    E poll();

    /*
        从队列头获取值,不移除
        Returns:如果队列非空返回队头值,否则返回null
     */
    E peek();

    /*
        检查队列是否为空
        Return:空返回true,否则返回false
     */
    boolean isEmpty();

    /*
        检查队列是否为满
        Return:满返回true,否则返回false
     */
    boolean isFull();
}

有序数组实现队列接口

import Day10Queue.Queue;

public class PriorityQueue2<E extends Priority> implements Queue<E> {
    Priority[] array;
    int size;

    public PriorityQueue2(int capacity) {
        array = new Priority[capacity];
    }

    @Override
    public boolean offer(E e) {
        if (isFull()){
            return false;
        }
        insert(e);
        size++;
        return false;
    }

    private void insert(E e) {
        int i = size-1;
        while (i >= 0 && array[i].priority() > e.priority()){
            array[i+1] = array[i];
            i--;
        }
        array[i+1] = e;
    }

    @Override
    public E poll() {
        if (isEmpty()){
            return null;
        }
        E e = (E) array[size-1];
        array[size-1] = null;
        size--;
        return e;
    }

    @Override
    public E peek() {
        if (isEmpty()){
            return null;
        }
        return (E) array[array.length - 1];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }
}

测试类

import org.junit.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

public class TestPriorityQueue2 {
    @Test
    public void poll(){
        PriorityQueue2<Entry> queue1 = new PriorityQueue2<>(5);
        queue1.offer(new Entry("task1",4));
        queue1.offer(new Entry("task2",3));
        queue1.offer(new Entry("task3",2));
        queue1.offer(new Entry("task4",5));
        queue1.offer(new Entry("task5",1));
        assertFalse(queue1.offer(new Entry("task6",7)));

        assertEquals(5, queue1.poll().priority());
        assertEquals(4, queue1.poll().priority());
        assertEquals(3, queue1.poll().priority());
        assertEquals(2, queue1.poll().priority());
        assertEquals(1, queue1.poll().priority());
        System.out.println(queue1.toString());
    }
}

四、堆实现

数据结构——堆

定义

计算机科学中,堆是一种基于树的数据结构,通常用完全二叉树实现。堆的特性如下:

        大顶堆,任意节点C与它的父节点P符合:P.value >= C.value

        小顶堆,任意节点C与它的父节点P符合:P.value <= C.value

        最顶层的节点(没有父亲),称之为root根节点

完全二叉树:除叶子节点那一层(最后一层)外,其余层都被填满(最后一层可填满可不填满)

特性:完全二叉树添加元素必须从左到右依次填满

特征

如果从索引0开始存储节点数据

        节点 i 的父节点为 floor((i-1)/2),当i>0时

        节点 i 的左子节点为 2i+ 1,右子节点为 2i + 2,当然它们需要 < size

如果从索引1开始存储节点数据

        节点 i 的父节点为 floor(i/2),当i>1时

        节点 i 的左子节点为 2i,右子节点为 2i + 1 ,同样需要 < size


大顶堆实现优先级队列

思路

根据大顶堆特性,root根节点就是优先级最高的元素,索引0位置就是要出队的元素,直接在队头出队进行删除

入堆新元素,加入到数组末尾(索引位置child)

不断比较新加入元素与它父亲节点(parrent)的优先级

        如果父节点优先级低,则向下移动,并找到下一个parrent

        直至父节点优先级更高或 child == 0 为止

交换堆顶和尾部元素,让尾部元素出队

(下潜)

        从堆顶开始,将父元素与两个孩子较大者交换

        直到父元素大于两个孩子,或没有孩子为止


元素优先级接口

public interface Priority {
    // 返回对象的优先级,约定数字越大,优先级越高
    // Returns:优先级
    int priority();
}

队列接口

import Day13PriorityQueue.Priority;

public interface Queue<E> {
    /*
        向队列尾部插入值
        Params:value-待插入值
        Returns:插入成功返回true,插入失败返回false
     */
    boolean offer(E e);

    /*
            从队列头获取值,并移除
            Returns:如果队列非空返回头部值,否则返回null
         */
    E poll();

    /*
        从队列头获取值,不移除
        Returns:如果队列非空返回队头值,否则返回null
     */
    E peek();

    /*
        检查队列是否为空
        Return:空返回true,否则返回false
     */
    boolean isEmpty();

    /*
        检查队列是否为满
        Return:满返回true,否则返回false
     */
    boolean isFull();
}

优先级队列的实现

import Day10Queue.Queue;

@SuppressWarnings("all")
public class PriorityQueue3<E extends Priority> implements Queue<E> {
    Priority[] array;
    int size;

    public PriorityQueue3(int capacity) {
        array = (Priority[]) new Priority[capacity];
    }

    @Override
    public boolean offer(E e) {
        /*
            入堆新元素,加入到数组末尾(索引位置child)
            不断比较新加入元素与它父亲节点(parrent)的优先级
            如果父节点优先级低,则向下移动,并找到下一个parrent
            直至父节点优先级更高或 child == 0 为止
         */
        if (isFull()){
            return false;
        }
        int child = size;
        size++;
        int parent = (child - 1) / 2;
        while (child >0 && e.priority() > array[parent].priority()) {
            array[child] = array[parent];
            child = parent;
            parent = (child - 1) / 2;
        }
        array[child] = e;
        return true;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        swap(0,size-1);
        size--;
        Priority e = array[size];
        array[size] = null;

        // 下潜
        down(0);
        return (E) e;
    }

    private void down(int parent) {
        int left = 2 * parent+1;
        int right = left + 1;
        // 假设父元素优先级最高
        int max = parent;
        if (left < size && array[left].priority() > array[max].priority()) {
            max = left;
        }
        if (right < size && array[right].priority() > array[max].priority()) {
            max = right;
        }
        // 有孩子优先级大于父节点
        if (max != parent) {
            swap(max,parent);
            down(max);
        }
    }

    private void swap(int i, int j) {
        Priority temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return (E) array[0];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }
}

 测试类

import org.junit.Test;
import static org.junit.jupiter.api.Assertions.*;

public class TestPriorityQueue3 {
    @Test
    public void test() {
        PriorityQueue3<Entry> queue = new PriorityQueue3<>(5);
        queue.offer(new Entry("task1",4));
        queue.offer(new Entry("task2",3));
        queue.offer(new Entry("task3",2));
        queue.offer(new Entry("task4",1));
        queue.offer(new Entry("task5",5));
        assertFalse(queue.offer(new Entry("task6",6)));

        assertEquals(5,queue.poll().priority());
        assertEquals(4,queue.poll().priority());
        assertEquals(3,queue.poll().priority());
        assertEquals(2,queue.poll().priority());
        assertEquals(1,queue.poll().priority());
    }
}

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

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

相关文章

IIOT工业物联网的标准与互操作性—SunIOT

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。一站式数智工厂解决方案服务商】 工业物联网&#xff08;IIoT&#xff09;正以惊人的速度重塑着工业领域的生产方式、运营模式和价值创造。然而&#xff0c;要实现工业物联网的广泛应用和充分发挥…

qt cmake自定义资源目录,手动加载资源(图片, qss文件)

1. 目录创建 因为使用非qtcreator或者自定义工程结构就没法自动加载图标&#xff0c;所以需要手动加载&#xff0c;这里使用vscode和自定义工程结构 vscode qt 环境搭建&#xff1a; https://blog.csdn.net/qq_51355375/article/details/140733495 qt 自定义工程结构参考(因使…

js chrome devtools 调试技巧

笔记 这一篇&#xff0c; 需要慢慢补充。 1. console 控制台 $0, 查看当前选中的元素getEventListener($0) 当前元素&#xff0c;包含的监听事件 老哥留步&#xff0c;支持一下。

高级I/O

目录 一、I/O概念 1.1、OS 如何得知外设中有数据可读取&#xff1f; 1.2、OS 如何处理从网卡中读取到的数据包&#xff1f; 二、五种I/O模型 2.1、阻塞I/O 2.2、非阻塞I/O 2.3、信号驱动 IO 2.4、IO 多路转接 2.5、异步 IO 三、高级I/O 3.1、同步通信 VS 异步通信 …

YOLO11改进|卷积篇|引入全维动态卷积ODConv

目录 一、【ODConv】全维动态卷积1.1【ODConv】卷积介绍1.2【ODConv】核心代码 二、添加【ODConv】卷积2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【ODConv】全维动态卷积 1.1【ODConv】卷积介绍 ODConv利用一种全新的多维注意力机…

12.1 Linux_进程间通信_管道

概述 什么是无名管道&#xff1a; 无名管道就是在内核中开辟了一块内存&#xff0c;进程1和进程2都可以访问这一块空间&#xff0c;从而实现通信。 当无名管道被创建时&#xff0c;父进程fd[0]指向管道的读端&#xff0c;fd[1]指向管道的写端。fork创建子进程后&#xff0c;…

4.人员管理模块(开始预备工作)——帝可得管理系统

目录 前言一、需求分析1.页面原型2.创建SQL 二、使用若依框架生成前后端代码1.添加目录菜单2.添加数据字典3.配置代码生成信息4.下载代码并导入项目5.快速导入方法 三、 总结 前言 提示&#xff1a;本篇讲解人员管理模块的开发的预备工作&#xff0c;包括需求分析、生成代码、…

点亮一个LED以及按键控制

目录 前言 LED 1.LED介绍 2.LED原理图 3.如何实现发光 按键 1.按键原理图 2.按键原理 按键控制LED 1.代码实现 2.软件消除抖动 软件消除抖动的原因 软件消抖如何实现 总结 前言 我们上节完成了开发环境的安装&#xff0c;本节我们就来实现我们的第一个程序吧(没安…

STM32的集成电路总线I2C

一、I2C简介 1.I2C总线特点 &#xff08;1&#xff09;两线制 I2C只需要SDA、SCL两根线来完成数据的传输和外围器件的扩展&#xff0c;器件地址采用软件寻址方式。 &#xff08;2&#xff09;多主机总线 I2C是一个真正的多主机总线&#xff0c;如果2个或多个主机同时初始化数据…

Day01-MySQL数据库介绍及部署

Day01-MySQL数据库介绍及部署 1、数据库服务概述介绍1.1 企业中为什么需要数据库&#xff1f;1.2 数据库服务作用1.3 数据库服务分类 2、数据库服务安装部署2.1 数据库版本应用2.2 数据库服务程序下载2.3 数据库软件安装方式2.3.1 二进制安装步骤 3、数据库服务初始化介绍3.1 安…

《15分钟轻松学 Python》教程目录

为什么要写这个教程呢&#xff0c;主要是因为即使是AI技术突起的时代&#xff0c;想要用好AI做开发&#xff0c;那肯定离不开Python&#xff0c;就算最轻量级的智能体都有代码块要写&#xff0c;所以不一定要掌握完完整整的Python&#xff0c;只要掌握基础就能应对大部分场景。…

react-问卷星项目(6)

实战 React常用UI组件库 Ant Design国内最常用组件库&#xff0c;稳定&#xff0c;强大Material UI国外流行TailWind UI 国外流行&#xff0c;收费 Ant Design 官网地址 这一章基本内容就是使用UI重构页面&#xff0c;也没有什么知识点&#xff0c;直接上代码 下载 npm ins…

git diff 查看到一行变动,但是目测无差异怎么办?

1. 目测无变化 直接用 git diff main.js 提示有一行变动&#xff0c;但是目测看不出来差异。 结果如图&#xff1a;up panel. 2. 大概是空格的问题&#xff0c;使用参数 --ws-error-highlightall $ git diff --ws-error-highlightall main.js结果如图: down panel.

【LeetCode: 19. 删除链表的倒数第 N 个结点 | 链表 + 快慢指针】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

大学生就业桥梁:基于Spring Boot的招聘系统

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

【操作系统】引导(Boot)电脑的奇妙开机过程

&#x1f339;&#x1f60a;&#x1f339;博客主页&#xff1a;【Hello_shuoCSDN博客】 ✨操作系统详见 【操作系统专项】 ✨C语言知识详见&#xff1a;【C语言专项】 目录 什么是操作系统的引导&#xff1f; 操作系统的引导&#xff08;开机过程&#xff09; Windows操作系…

JavaScript-下篇

上篇我们学习了&#xff0c;一些基础语法和函数&#xff0c;现在我们学习下篇&#xff0c;主要包括,对象和事件。而对象又包括&#xff0c;数组Arrays&#xff0c;String字符串&#xff0c;BOM&#xff0c;DOM等 JS对象 Arrays数组 数组是一种特殊的对象&#xff0c;用于存储…

【多线程】多线程(8):单例模式:阻塞队列

【阻塞队列】 阻塞队列是在普通的“先进先出”队列的基础上&#xff0c;做出了扩充&#xff0c;可以组成「生产者消费者模型」 1.线程安全性 标准库是原有的队列Queue和其子类&#xff0c;默认都是“线程不安全的”&#xff0c;而阻塞队列是“线程安全的” 2.具有阻塞特性 …

【pytorch】张量求导3

再接上文,补一下作者未补完的矩阵运算的坑。 首先贴一下原作者的图,将其转化为如下代码: import torch import torch.nn as nn import torch.optim as optim# 定义一个简单的两层神经网络 class TwoLayerNet(nn.Module):def __init__(self):super(TwoLayerNet, self).__in…

Markdown 语法详解大全(超级版)(二)

Markdown 语法详解大全(超级版)&#xff08;二&#xff09; Markdown 语法详解大全(超级版)&#xff08;一&#xff09; Markdown 语法详解大全(超级版)&#xff08;二&#xff09; Markdown 语法详解大全(超级版)&#xff08;三&#xff09; &#xff08;歌词节选&#xff09…