java数据结构--优先级队列

news2024/11/22 23:43:37

一.概念

 

优先级队列是一种特殊类型的队列,它根据每个元素的优先级进行排序和访问。较高优先级的元素将在较低优先级的元素之前被处理。

优先级队列可以使用不同的数据结构实现,包括数组、链表或二叉堆。其中,二叉堆是实现优先级队列的常见选择。二叉堆是一个完全二叉树,具有以下特性:

  1. 每个节点的值都大于或等于其子节点的值(最大堆),或者每个节点的值都小于或等于其子节点的值(最小堆)。
  2. 二叉堆是一个完全二叉树,意味着除最后一层外,每一层都是满的,并且最后一层的节点都尽可能地靠左排列。

优先级队列的主要操作包括:

  1. 插入(add):将一个元素插入到队列中,并根据其优先级进行排序。
  2. 删除最高优先级元素(poll):从队列中删除具有最高优先级的元素。
  3. 查看最高优先级元素(peek):查看具有最高优先级的元素,而不删除它。

优先级队列在各个领域中的应用非常广泛,例如任务调度、数据压缩、网络路由等

二.队列Queue接口

 我们先定义好Queue接口,然后实现它

public interface Queue<E> {



    /**
     * 向队列尾添加元素
     * @return 添加成功返回true,添加失败返回false
     */
     boolean add(E e);

    /**
     * 从队列头删除一个节点,并取出该元素
     * @return 队头元素
     */
    E pull();

    /**
     * 从队列头取出该元素,但是不删除该节点
     * @return 队头元素
     */
    E peek();

    /**
     * 判断队列是否为空
     * @return 空为true,非空为false
     */
    boolean isEmpty();

    /**
     * 判断队列是否为满
     * @return 满为true,不满为false
     */
    boolean isFull();

}

三.优先级接口Proiroity,任务类Task

我们定义优先级接口Proiroity,它提供一个proiority()方法,获取元素的优先级

public interface Priority {

    //返回优先级
    int priority();

}

我们定义任务类Task,作为放入优先级队列中的元素

/**
 * 模拟任务类,有优先级的任务
 */
public class Task implements Priority{

    String name;

    int priority;

    public Task(String name,int priority){
        this.name = name;
        this.priority = priority;
    }



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

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

四.无序数组实现优先级队列

 

/**
 * 无序数组实现优先级队列
 * @param <E>
 */
public class DisOrderArrayPriorityQueue<E extends Priority> implements Queue<E>,Iterable<E> {

    //数组
    E[] array;
    //元素的个数,也可以作为尾指针
    int size;

    @SuppressWarnings("all")
    public DisOrderArrayPriorityQueue(int capacity){
        array = (E[]) new Priority[capacity];
        size = 0;
    }

    /**
     * 返回优先级最大的索引位置
     * @return
     */
     private int maxPriority(){
        int max = 0;
         for (int i = 0; i < size; i++) {
             if(array[max].priority() < array[i].priority()){
                 //将max索引设置为i
                 max = i;
             }
         }
         return max;
     }

    /**
     * 移除优先级最大的元素
     *
     *            m
     *  0 1 2 3 4 5 6
     *  a b c d e f g
     *
     *  index=5,
     *
     * @param index
     */
     private void remove(int index){
         if(index < size){
             //当该索引不是最后一个位置时需要移动数组
             System.arraycopy(array,index+1,array,index,size-1-index);
         }
         //否则不需要移动数组
         //都需要让size--;
         size--;
     }

    /**
     * 添加元素,直接在末尾添加就可以了
     * @param e
     * @return
     */
    @Override
    public boolean add(E e) {
       //先判断是否满
        if (isFull()) {
            return false;
        }
        array[size] = e;
        size++;
        return true;
    }

    /**
     * 移除优先级最大的元素
     * @return
     */
    @Override
    public E pull() {
        if(isEmpty()){
            return null;
        }
        int max = maxPriority();
        E e = array[max];
        remove(max);
        return e;
    }

    /**
     * 返回优先级最大的元素
     * @return
     */
    @Override
    public E peek() {
        if(isEmpty()){
            return null;
        }
        int max = maxPriority();
        return array[max];
    }

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

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

    //遍历
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {

            int p = 0;

            @Override
            public boolean hasNext() {
                return p != size;
            }

            @Override
            public E next() {
                E e = array[p];
                p++;
                return e;
            }
        };
    }
}

五.有序数组实现优先级队列

/**
 * 有序数组实现优先级队列
 * @param <E>
 */
public class OrderArrayPriorityQueue<E extends Priority> implements Queue<E> ,Iterable<E>{

    E[] array;

    int size;

    @SuppressWarnings("all")
    public OrderArrayPriorityQueue(int capacity){
        array = (E[]) new Priority[capacity];
        size = 0;
    }


    private void insertTo(E e){
        int i = size - 1;

        while ( i >= 0 && array[i].priority() > e.priority() ){
             //将i后移
            array[i+1] = array[i];
            i--;
        }
        //插入到正确的位置
        array[i+1] = e;
    }




    @Override
    public boolean add(E e) {
        if(isFull()){
            return false;
        }
        //先插入到正确的索引位置
        insertTo(e);
        size++;
        return true;
    }

    /**
     * 移除优先级最高的元素(最后一个元素)
     * @return
     */
    @Override
    public E pull() {
        if(isEmpty()){
            return null;
        }
        E e = array[size-1];
        //让size--
        size--;
        array[size] = null; //help GC
        return e;
    }

    /**
     * 返回队列优先级最高的元素(最后一个元素)
     * @return
     */
    @Override
    public E peek() {
       if(isEmpty()){
           return null;
       }
       return array[size-1];
    }

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

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


    //遍历
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {

            int p = 0;

            @Override
            public boolean hasNext() {
                return p != size;
            }

            @Override
            public E next() {
                E e = array[p];
                p++;
                return e;
            }
        };
    }



}

六.无序数组和有序数组的区别

对于无序数组来说,每次添加元素是直接添加在数组的末尾,添加起来方便,但是取出优先级最高的元素需要进行一次排序,也就是取出复杂;

对于有序数组来说,每次取出优先级最高的元素就是取去数组末尾的元素,但是添加元素时,需要进行一次插入排序,找到合适的位置,也就是添加复杂

七.大顶堆实现优先级队列

1.大顶堆

 

2.基于数组的实现

 堆虽然是非线性的数据结构,但是我们可以利用数组来存储他的节点,这是有规律的,

  节点i的父节点是floor((i-1)/2)

 节点i的左子节点是2i + 1, 右子节点是2i + 2

下面我们用数组来实现堆的优先级队列

/**
 * 数组实现大顶堆,实现优先级队列
 * @param <E>
 */
public class HeapArrayPriorityQueue<E extends Priority> implements Queue<E>  {


    E[] array;

    int size;

    @SuppressWarnings("all")
    public HeapArrayPriorityQueue(int capacity){
        array = (E[]) new Priority[capacity];
        size = 0;
    }


    /**
     * 添加元素
     *
     * 1.首先将元素添加到数组的末尾
     * 2.然后让size++;
     * 3.然后调整堆使其符合大顶堆
     *
     *
     * @param e
     * @return
     */
    @Override
    public boolean add(E e) {
       if(isFull()){
           return false;
       }
       //先记录child的索引位置,就是在数组的末尾添加
        int child = size++;
       //找到他的父节点的索引位置
        int parent = (child - 1)/2;
        //然后比较要添加元素的优先级和parent的优先级
        //而且child必须是大于0的,当child==0时,表示到堆顶了,就不需要再调整了
        while ( child > 0 && e.priority() > array[parent].priority() ){
            //当e的优先级大于parent的优先级时
            //parent要向下沉到child处
            array[child] = array[parent];
            //然后将child的索引位置设置为parent
            child = parent;
            //继续找到child的父节点位置
            parent = (child - 1)/2;
        }
        //调整完成后,child处就是要插入的正确位置
        array[child] = e;

        return true;
    }

    @Override
    public E pull() {
        if(isEmpty()){
            return null;
        }
        //先交换0处和最后一个位置
        swap(0,size-1);
        size--;
        E e = array[size];
        array[size] = null; //help GC

        //调整堆,也就是让堆顶元素下沉到合适的位置
        adjust(0);

        return e;
    }

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

    /**
     * 交换数组中两个索引位置的值
     * @param i
     * @param j
     */
    private void swap(int i ,int j){
        E e  = array[i];
        array[i] = array[j];
        array[j] = e;
    }

    /**
     * 调整堆,从堆顶开始
     * @param parent
     */
    private void adjust(int parent){
       int left = parent * 2 + 1;
       int right = left + 1;
       //假设parent最大
        int max = parent;
        //分别判断左孩子,右孩子与parent的优先级
        if(left > 0 && array[left].priority() > array[parent].priority()){
            max = left;
        }
        if(right > 0 && array[right].priority() > array[parent].priority()){
            max = right;
        }
        //如果max!=parent,就需要交换max和parent
        if(max != parent){
            swap(max,parent);
            //递归调用,将max作为parent继续调用
            adjust(max);
        }
    }



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

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

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

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

相关文章

在已有的虚拟环境中升级python版本

对于现有的虚拟环境&#xff0c;想升级python版本方法&#xff0c;试了无数的方法终于找对了。 1.首先activate对应的虚拟环境&#xff0c;然后输入下面的命令&#xff1a; conda install python3.8 建议加上镜像源 ​conda install python3.8 -i https://pypi.tuna.tsingh…

长虹智能电视使用123

1、开机 在接通电源的情况下&#xff0c;长虹智能电视开机有两种方式。 方式1&#xff1a; 按电视右下角开机按钮 方式2&#xff1a; 按电视遥控器开机按钮 长虹智能电视开机后会进入其操作系统&#xff08;安卓&#xff09;。 屏幕左右双箭头图表&#xff0c;手指点击会…

如何查看Android 包依赖关系

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、查看依赖关系3.1 方式一3.2 方式二…

C语言——判断1~100中的奇数

方式一、 while&#xff0c;if语句 #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int i1;while(i<100){if(1 i%2)printf("%d ",i);i;}return 0; } 方式二、 while&#xff0c;if语句 #define _CRT_SECURE_NO_WARNINGS 1#include&…

智慧工地综合管理平台-项目整体需求规格说明书

引言 定位与目标 智慧工地是一种现代化的管理方式,目标是通过应用现代科技手段,对施工现场的设备、人员、物资等信息全面掌控,减少工地事故的发生,提高施工质量和安全性,同时也能够降低成本,提高效益,实现建筑施工的数字化、智能化和可持续发展,为城市建设和社会发展…

绿联DX4600 AList部署及挂载阿里云盘

写在前面 ​ 因为云盘总是封禁已经转存的文件&#xff08;珍惜影片&#xff09;&#xff0c;实在受不了了&#xff0c;就像购买个NAS构建私人云存储&#xff0c;正好趁着双11购入了绿联的DX4600&#xff0c;本来想购入群晖或者威联通等专业NAS&#xff0c;因为不想折腾&#x…

算法秘籍-王一博 | 数据结构与算法

⭐简单说两句⭐ 作者&#xff1a;后端小知识 CSDN个人主页&#xff1a;后端小知识 &#x1f50e;GZH&#xff1a;后端小知识 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂&…

一分钟带你了解易货:来龙去脉,古往今来

原始社会&#xff0c;没有货币&#xff0c;人类没有货币&#xff0c;用捕猎来的兽皮换取需要的野果&#xff0c;用一头羊换几只鸡&#xff0c;等等之类&#xff0c;都属于最早的交换。那个时候&#xff0c;人类没有价值的定义&#xff0c;属于最原始的交换。 直到私有制的形成&…

IP协议相关技术

文章目录 IP协议相关技术仅凭IP无法完成通信DNSARP IP协议相关技术 仅凭IP无法完成通信 人们在上网的时候其实很少直接输入某个具体的IP地址。 在访问Web站点和发送、接收电子邮件时&#xff0c;我们通常会直接输入Web网站的地址或电子邮件地址等那些由应用层提供的地址&…

嵌软工程师要掌握的硬件知识2:一文看懂什么是开漏和推挽电路(open-drain / push-pull)

文 / 黑猫学长 本文根据笔者个人工作/学习经验整理而成,如有错误请留言。 文章为付费内容,已加入原创侵权保护,禁止私自转载及抄袭。 文章所在专栏: 嵌软工程师要掌握的硬件知识 1 推挽(push pull)电路 1.1 理解什么是推挽电路 - 详细介绍 如图所示,Q3是个NPN型三极管…

掌动智能:UI自动化测试工具产品功能和优势

UI自动化测试工具是一种软件工具&#xff0c;用于模拟用户与应用程序的交互&#xff0c;检查应用程序的用户界面是否按预期工作。这些工具允许开发人员编写测试脚本&#xff0c;以模拟用户操作&#xff0c;例如点击按钮、输入文本、导航菜单等&#xff0c;然后验证应用程序的响…

如何通过对话式机器人流程自动化 (CRPA),改善客户服务?

对话式机器人流程自动化&#xff08;CRPA&#xff09;系统在企业内部的应用越来越广泛&#xff0c;尤其在客户服务部门&#xff0c;其潜力得到了充分发挥。这种系统将自动化与人工智能技术的最新进步相结合&#xff0c;以提升和优化各类流程的效率。 然而&#xff0c;什么是CRP…

【qemu逃逸】XCTF 华为高校挑战赛决赛-pipeline

前言 虚拟机用户名: root 无密码 设备逆向与漏洞分析 程序没有去符合, 还是比较简单. 实例结构体如下: 先总体说一下流程: encode 为 base64 编码函数, decode 为 base64 解码函数. 然后 encPipe 和 decPipe 分别存放编码数据和解码数据, 分别有四个: 其中 EncPipeLine 中…

数据结构-栈和队列力扣题

目录 有效的括号 用队列实现栈 用栈实现队列 设计循环队列 有效的括号 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 这道题可以用栈来解决&#xff0c;先让字符串中的左括号 ( &#xff0c; [ &#xff0c; { 入栈&#xff0c;s指向字符串下…

昇腾CANN 7.0 黑科技:大模型推理部署技术解密

CANN作为最接近昇腾AI系列硬件产品的一层&#xff0c;通过软硬件联合设计&#xff0c;打造出适合昇腾AI处理器的软件架构&#xff0c;充分使能和释放昇腾硬件的澎湃算力。针对大模型推理场景&#xff0c;CANN最新发布的CANN 7.0版本有机整合各内部组件&#xff0c;支持大模型的…

笔记本电脑的麦克风没有声音

笔记本电脑的麦克风没有声音是一个常见的问题&#xff0c;可能是由于以下几个原因导致的&#xff1a; 第一&#xff0c;麦克风没有启用或者被禁用了。在Windows系统中&#xff0c;右键单击任务栏上的音量图标&#xff0c;选择“录音设备”&#xff0c;在弹出窗口中找到麦克风&a…

阿里云Intel Xeon Platinum可扩展处理器性能说明

阿里云Intel Xeon Platinum可扩展处理器性能如何&#xff1f;目前云服务器ECS经济型e实例采用该款CPU型号&#xff0c;正好阿里云服务器网购买了一台2核CPU、2G内存、3M固定带宽、40G ESSD Entry云盘&#xff0c;一年优惠价99元&#xff0c;第二年续费不涨价依旧是99元一年&…

2023最新版JavaSE教程——第3天:流程控制语句之顺序语句与分支语句

目录 一、顺序结构二、分支语句2.1 if-else条件判断结构2.1.1 基本语法2.1.2 应用举例2.1.3 if...else嵌套2.1.4 其它说明2.1.5 练习 2.2 switch-case选择结构2.2.1 基本语法2.2.2 应用举例2.2.3 利用case的穿透性2.2.4 if-else语句与switch-case语句比较2.2.5 练习 流程控制语…

windows上 Nexus 批量上传 maven依赖npm依赖

windows上 Nexus 批量上传 maven依赖/npm依赖 前言&#xff1a;windows系统上要有git环境&#xff0c;不然sh文件执行不了 1.批量上传maven依赖 设置脚本&#xff0c;把脚本放在依赖包的根目录执行&#xff0c;脚本名为upload.sh #!/bin/bash# 定义变量 while getopts &quo…

陪玩2.0升级版源码/价值18500元的最新商业版游戏陪玩语音聊天系统源码

陪玩2.0升级版源码&#xff0c;价值18500元的最新商业版游戏陪玩语音聊天系统源码。 修复部分逻辑以及bug 修复bug&#xff1a;店员拒单后&#xff0c;退款会退到店员账号里而不是用户账户里。 修复bug&#xff1a;客户在盲盒下单后&#xff0c;马上取消了订单&#xff0c;但…