数据结构 - 优先级队列(堆)

news2024/12/28 2:54:38

文章目录

  • 前言
  • 1.介绍优先级队列
  • 2. 认识堆
  • 3. 实现优先级队列
    • 3.1 了解优先级队列的构造方法:
    • 3.2 使用优先级队列解决问题:
  • 总结


前言

本篇PriorityQueue优先级队列的介绍其底层是堆,关于堆的认识,使用优先级队列能解决的一些问题;如有错误,请在评论区指正,让我们一起交流,共同进步!


本文开始

1.介绍优先级队列

优先级队列:它的底层是一种堆的数据结构,它以顺序结构存储,是一个一维数组;

既然底层是堆,就来了解一下!

2. 认识堆

认识堆的特点:有两种堆类型
① 小根堆:父节点小于左右孩子节点,不能保证左右孩子谁大; =》使用优先级队列就创建了小根堆,想要创建大根堆需要自己给比较器(根据自定义规则比较,用于节点交换);
② 大根堆:父节点大于左右孩子节点,不能保证左右孩子谁大;
③ 堆还是完全二叉树:可以使用顺序存储;非完全二叉树存储,为了还原二叉树还需要存储空节点,浪费空间 - 》堆为什么可以顺序存储的原有;

代码实现小根堆:
向下调整(父节点向下走):从最后一颗子树开始,父节点与子节点比较大小是否交换,直到不用比较就确定了小根堆;


    /**
     * 建堆的时间复杂度:
     * O(n)
     */
//求出最后一个父节点,因为是顺序存储的-1就是下一颗树的父节点
 public void createHeap(int[] array) {
        for (int parent = (usedSize - 1) / 2; parent >= 0; parent--) {
            //获取最后一个子树父节点,usedSize记录数组中存储的个数
            //传递父节点和孩子节点最大的范围
            shiftDown(parent,usedSize);
        }
    }

    /**
     * root 是每棵子树的根节点的下标
     *  len  是每棵子树调整结束的结束条件
     * 向下调整的时间复杂度:O(logn) ;最坏换树的高度
     */
    private void shiftDown(int root,int len) {
        //向下调整需要每个子树的父节点
        int child = 2 * root + 1;//求出左孩子节点位置
        while (child < len) {
            //获取孩子节点最大值下标
            //防止右孩子下标越界,需要判断
            if(child + 1 < len && elem[child] < elem[child + 1]) {
                child++;
            }
            //比较父子节点大小
            if(elem[child] > elem[root]) {
                swap(elem,child,root);
                //调整父子节点下标位置
                child = root;
                root = 2 * child + 1;//再次获取左孩子节点下标
            }else {
                //父节点大于子节点直接跳出
                break;
            }
        }
  }
    //交换函数
    private void swap(int[] elem, int child, int root) {
        int tmp = elem[child];
        elem[child] = elem[root];
        elem[root] = tmp;
    }

代码实现大根堆
向上调整(孩子节点向上走):

private void shiftUp(int child) {
        //求出它的父节点下标
        int parent = (child - 1) / 2;
        //child==0最后一个节点不用比较
        while (child > 0) {
            //比较父子节点大小
            if(elem[child] > elem[parent]) {
                //交换
                swap(elem,child,parent);
                //移动父子节点下标,可能不止移动一次(子节点向上)
                child = parent;
                parent = (child - 1) / 2;//获得更上一级的父节点下标
             }else {
                //父节点小于子节点直接跳出
                break;
            }
        }
}

3. 实现优先级队列

了解大根堆,小根堆就可以实现优先级队列!
代码实现优先级队列(以大根堆为例):

public class PriorityQueue {
    public int[] elem;
    public int usedSize;
    public PriorityQueue() {
        int[] elem = new int[10];
    }

    //交换函数
    private void swap(int[] elem, int child, int root) {
        int tmp = elem[child];
        elem[child] = elem[root];
        elem[root] = tmp;
    }


    /**
     * 入队:仍然要保持是大根堆
     */
    public void push(int val) {
        //插入
        if(isFull()) {
            //扩增
            Arrays.copyOf(elem,2*elem.length);
            return;
        }
        //没满就在最后位置插入
        elem[usedSize] = val;
        //向上调整即可
        shiftUp(usedSize);
        usedSize++;
    }

   
    public boolean isFull() {
        return usedSize == elem.length;
    }

    /**
     * 出队删除:每次删除的都是优先级高的元素
     * 仍然要保持是大根堆
     */
    public void pollHeap() {
        if(isEmpty()) {
            return;
        }
        //交换首尾
        int end = usedSize - 1;
        swap(elem,0,end);
        //向下调整范围需要-1,因为删除了一个元素
        shiftDown(0,--usedSize);
    }
//判断是否为空
    public boolean isEmpty() {
        return usedSize == 0;
    }

    /**
     * 获取堆顶元素
     */
    public int peekHeap() {
        if(isEmpty()) {
            return -1;
        }
        return elem[0];
    }
}

3.1 了解优先级队列的构造方法:

无参构造:默认大小11

在这里插入图片描述

有一个整形参数的构造:

在这里插入图片描述

两个参数(整形,比较规则)的构造

在这里插入图片描述

3.2 使用优先级队列解决问题:

1.top-k问题:
例如取前k个最小 / 最大的值;
2.堆排序
①升序(1,2,3…):大根堆
使用原因:大根堆堆顶元素一定最大的,将堆顶元素与堆末尾元素交换,再向下调整,重新得到大根堆;这样每次都会把最大的放到最后,再次到堆顶的时候,堆顶后面的元素已经有序了,依次弹出即可;
②降序(4,3,2…):小根堆
使用原有:小根堆堆顶元素一定最小的,将堆顶元素与堆末尾元素交换,再向下调整,重新得小根堆;这样每次都会把最小的放到最后,再次到堆顶的时候,堆顶后面的元素已经降序有序了,依次弹出即可;


总结

✨✨✨各位读友,本篇分享到内容如果对你有帮助给个👍赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!

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

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

相关文章

day12_Django的基本操作

文章目录创建django项目项目-各个文件的含义app-各个文件的含义MVT运行&#xff0c;查看是否创建项目框架成功ORM迁移->在数据库中形成对应的 表通过类名 对象的方法完成数据库的增删查改操作通过模型类&#xff08;shell&#xff09;的方法操作数据表后台管理进入后台http:…

dvwa靶场的搭建过程

dvwa靶场的搭建过程 记录一下自己重新开始学习web安全之路①。 首先一个要搭建一个网站需要的准备 服务器 – 操作系统 windows linux&#xff08;可以将电脑当成服务器&#xff09; 数据库 MySQL sql server Oracle access 、、、、作用&#xff1a;存储数据 中间件 apac…

零基础学MySQL(五)-- 详细讲解数据库中的常用函数

目录&#x1f387;一、聚合函数1️⃣count 函数&#xff08;1&#xff09;基本语法&#xff08;2&#xff09;基本练习&#xff08;3&#xff09;注意细节2️⃣sum 函数&#xff08;1&#xff09;基本语法&#xff08;2&#xff09;基本练习&#xff08;3&#xff09;注意细节3…

opencv常用函数

1)读视频 img cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if vc.isOpened():ret, frame vc.read() else:ret False while ret:#此处省略具体的操作ret, frame vc.read() # 读下一帧 vc.release() 2&#xff09;保存视频 def mk_video_writer(vc, path&#xff0c;frame_…

MASA Stack 1.0 发布会讲稿——生态篇

2022年运营回顾 贡献者 首先感谢贡献者们为MASA Stack社区所作的积极贡献&#xff0c;这些贡献者给我们提出了很多宝贵的建议&#xff0c;更是积极的提交PR帮助我们一起让产品更健壮&#xff0c;更完善&#xff0c;还在各种场合推广我们的解决方案&#xff0c;非常给力&#x…

智能工厂以MES系统为基础,实现"信息化减人,自动化换人"

MES是一种生产信息化的管理系统&#xff0c;它适用于制造业的车间实施层面。MES能够为企业提供生产数据、项目看板、库存、成本、工装、生产计划、计划排程、质量、人力资源、采购、生产过程控制、底层数据集成分析、上层数据集成分解等管理模块&#xff0c;为企业打造一个扎实…

史上最详细JUC教程之Synchronized与锁升级详解

在Java早期版本中&#xff0c;synchronized属于重量级锁&#xff0c;效率低下&#xff0c;因为监视器锁&#xff08;monitor&#xff09;是依赖于底层的操作系统的Mutex Lock来实现的&#xff0c;挂起线程和恢复线程都需要转入内核态去完成&#xff0c;阻塞或唤醒一个Java线程需…

JavaSE学习day4_02 数组(超级重点)

3.数组 3.1什么是数组 数组就是存储数据长度固定的容器&#xff0c;存储多个数据的数据类型要一致。 3.2数组定义格式 3.2.1第一种&#xff08;常用&#xff09; 数据类型[] 数组名 示例&#xff1a; int[] arr; double[] arr; char[] arr; 3.2.2第二种(在…

pandas——字符串处理【建议收藏】

pandas——字符串处理 作者&#xff1a;AOAIYI 创作不易&#xff0c;如果觉得文章不错或能帮助到你学习&#xff0c;记得点赞收藏评论一下哦 文章目录pandas——字符串处理一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.cat() 拼接字符串2.split()切片字符串…

Viper+MSF:靶机代理转发上线学习

本文仅为代理转发学习&#xff0c;在本地环境测试验证&#xff0c;无其它目的&#xff0c;请勿用于未经授权的测试 说明&#xff1a; 之前学习的代理转发上线&#xff0c;近期也做实验通过Viper&#xff0c;利用MSF实现了多重代理转发上线靶机&#xff0c;过程有些繁琐&#x…

【Linux】-- 进程信号(认识、应用)

目录 信号初识 生活中的信号 Linux中的信号 产生信号 核心转储 软件条件产生信号的样例 系统调用接口 raise kill abort 闹钟 硬件异常产生信号 如何理解除0错误 如何理解野指针 / 越界错误 总结 信号初识 &#xff08;信号和信号量是两个东西&#xff09; 生…

java web命令学习笔记

本博文源于笔者自学java web&#xff0c;博文包含了jsp脚本代码、jsp声明、jsp表达式、注释、jsp指令等内容说明&#xff0c;并书写对应的案例。即可观看&#xff0c;也可收藏。 文章目录1.jsp脚本代码2.JSP声明3.jsp表达式4.注释5.JSP指令5.1 page指令5.2 include指令1.jsp脚本…

《霍格沃茨之遗》席卷Steam周榜 哈迷们出手了!

自上上周起&#xff0c;《霍格沃茨之遗》就打败了长期霸榜王Steam Deck&#xff0c;夺得了Steam周榜冠军&#xff0c;果然魔法的力量不容小觑。 而在最新公开的周榜&#xff08;2 月 6 日~2 月 12 日&#xff09;中&#xff0c;《霍格沃茨之遗》更是强势席卷榜单&#xff0c;四…

​网易游戏实时 HTAP 计费风控平台建设

本文整理自网易互娱资深工程师, Flink Contributor, CDC Contributor 林佳&#xff0c;在 FFA 实时风控专场的分享。本篇内容主要分为五个部分&#xff1a; 实时风控业务会话会话关联的 Flink 实现HTAP 风控平台建设提升风控结果数据能效发展历程与展望未来 众所周知&#xff…

【GlobalMapper精品教程】045:空间操作(2)——相交(Intersect)

GlobalMapper提供的空间分析(操作)的方法有:交集、并集、单并集、差异、对称差集、相交、重叠、接触、包含、等于、内部、分离等,本文主要讲述相交工具的使用。 文章目录 一、实验数据二、符号化设置三、相交运算四、结果展示五、心灵感悟一、实验数据 加载配套实验数据(…

初始C++(三):引用

文章目录一.引用的概念二.引用的使用1.引用作为输出型参数2. 引用作为函数返回值3.const引用三.引用的一些小问题四.引用和指针五.引用和指针的区别一.引用的概念 引用的作用是给一个已经存在的变量取别名&#xff0c;编译器不会为引用变量开空间&#xff0c;引用变量和被他引…

一般人我劝你不要自学软件测试!!!

本人5年测试经验&#xff0c;在学测试之前对电脑的认知也就只限于上个网&#xff0c;玩个办公软件。这里不能跑题&#xff0c;我为啥说&#xff1a;自学软件测试&#xff0c;一般人我还是劝你算了吧&#xff1f;因为我就是那个一般人&#xff01; 软件测试基础真的很简单&…

九龙证券|“春季躁动”行情要来?1月新增投资者数大增

新增投资者数量在上一年12月触及多年新低后&#xff0c;2023年1月份开端呈现反弹。 在新增投资者数量之外&#xff0c;近段时刻以来&#xff0c;包含A股商场股票成交额、北向资金净买入额、两融资金规划及成交额在内多个商场目标也呈现回暖的特征&#xff0c;目前A股商场交投氛…

SQL数据查询——连接查询

文章目录一、等值和非等值连接查询1.等值连接查询2.非等值连接查询二、自连接与非自连接三、内连接与外连接1.内连接2.外连接使用左外连接还是右外连接&#xff1f;满外连接四、UNION 的使用使用 UNION 还是 UNION ALL &#xff1f;五、各种形式集合关系的SQL实现六、语法差异注…

动态SQL使用【JavaEE】

动态SQL使用 1. if 标签 判断一个参数是否有值&#xff0c;如果没值&#xff0c;那么就会隐藏 if 中的 sql 语法&#xff1a; <if test"username!null">username#{username} </if>表达式&#xff1a;username 的参数是否为空 如果结果为 true&#xff0c…