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

目录

一、优先级队列

1.1 堆

1.2 PriorityQueue接口

二、模拟实现优先级队列

2.1 初始化

2.2 创建大根堆 (向下调整)

2.3 堆的插入

2.4 堆的删除

2.5 堆排序

总结


一、优先级队列

优先级队列是一种特殊的队列,其出队顺序与入队顺序无关,而与优先级相关。其常见的实现方式就是使用作为底层数据结构。

1.1 堆

堆将所有元素按完全二叉树顺序存储方式存储在一个一维数组中,堆还分为大根堆小根堆

大根堆:每个结点的值都大于其子结点的值,最大值总是在堆顶。

小根堆:每个结点的值都小于其子结点的值,最小值总是在堆顶。

【完全二叉树的性质】

一棵有 n 个结点的完全二叉树,对于其编号为 i 的结点有:

  • 若 i > 0,父结点编号:[(i-1) / 2];若 i = 0,则 i 为根结点编号,无父结点。
  • 若 2i+1 < n,左孩子编号:2i+1;反之无左孩子。
  • 若 2i+2 < n,右孩子编号:2i+2;反之无右孩子。

1.2 PriorityQueue接口

在 Java 中提供了 PriorityQueue 和 PriorityBlockingQueue 接口来表示优先级队列,其中 PriorityQueue 线程不安全的,PriorityBlockingQueue 是线程安全的。

【PriorityQueue 的性质】

  • PriorityQueue 中放置的元素必须能够比较大小,否则会抛 ClassCastException。
  • 不能插入 null 对象,否则会抛 NullPointerException。
  • 没有容量限制,可以任意插入元素,其内部会自动扩容。
  • 插入和删除元素的时间复杂度为 O(log_{2}N)
  • PriorityQueue 底层使用了数据结构,默认情况下是小根堆

【构造方法】

方法说明
PriorityQueue()创建一个空的优先级队列,默认容量是11
PriorityQueue(int initialCapacity)创建一个初始容量为 initialCapacity (不能小于1) 的优先级队列
PriorityQueue(Collection<? extends E> c)用一个集合来创建优先级队列

【操作方法】 

方法说明
boolean offer(E e)插入元素 e
E poll()移除优先级最高的元素并返回
E peek()获取优先级最高的元素
int size()获取优先级队列中有效元素个数
boolean isEmpty()判断优先级队列是否为空
void clear()清空

二、模拟实现优先级队列

2.1 初始化

public class MyHeap {
    public int[] element;//定义数组以实现优先级队列(堆)
    public int usedSize;//记录堆中有效元素个数
    
    public MyHeap() {
        this.element = new int[10];
    }

    //初始化 element 数组
    public void initElement(int[] array) {
        for (int i = 0; i < array.length; i++) {
            //存入元素
            element[i] = array[i];
            //记录元素个数
            usedSize++;
        }
    }
}

2.2 创建大根堆 (向下调整)

① 初始令 parent 引用指向最后一棵子树的根结点进行调整,调整完一棵子树后,令 parent-- 前往其上一棵子树进行调整,直至调整完下标为 0 的根结点及其子树。

② 首先确保该根结点有左孩子的情况下,进入向下调整的过程,先令 child 引用指向孩子结点最大值

再比较 parent 与 child 大小,若 child 比 parent 大,则交换,交换后 parent 引用指向当前 child 引用,child 引用指向 parent 左孩子结点开始调整其下方子树,直至其下方不存在子树;

反之无需交换,直接结束循环。

    //创建大根堆:采用向下调整策略
    public void createHeap() {
        //从最后一棵子树开始调整,依次往前,直至根结点
        //父亲结点 = (孩子结点-1) / 2
        //usedSize-1 是树中最后一个结点
        for (int parent = (usedSize-1-1) / 2; parent >= 0; parent--) {
            //向下调整
            siftDown(parent,usedSize);
        }
    }

    //向下调整
    private void siftDown(int parent, int length) {
        //左孩子结点 = 父亲结点*2 + 1
        int child = parent*2 + 1;

        //首先保证该结点有左孩子结点
        while (child < length) {

            //确定该结点有右孩子结点,再进行比较
            //保证 child 引用指向孩子结点中最大值
            if ((child+1) < length && element[child] < element[child+1]) {
                //若右孩子的值大于左孩子,则 child 引用指向右孩子
                child = child + 1;
            }

            if (element[child] > element[parent]) {
                //若 child 比 parent 大,则交换元素
                swap(child, parent);

                //parent 指向 child 位置,向下调整至下方无子树
                parent = child;
                child = parent*2 + 1;
            } else {
                //子结点都比父结点小
                break;
            }
        }
    }

    //交换元素
    private void swap(int i, int j) {
        int tmp = element[i];
        element[i] = element[j];
        element[j] = tmp;
    }

2.3 堆的插入

将 value 存放至最后一个结点,开始向上调整。

② 在向上调整的过程中,只需比较 value 与当前的父亲结点大小,若需要交换,交换后 child 指向 parent,parent 指向 child 父结点;反之调整结束。

    //入堆
    public void offer(int value) {
        if (isFull()) {
            element = Arrays.copyOf(element, 2*element.length);
        }
        //将 value 放至最后一个结点
        element[usedSize] = value;
        //向上调整
        siftUp(usedSize);

        usedSize++;
    }

    private boolean isFull() {
        return usedSize == element.length;
    }

    //向上调整
    public void siftUp(int child) {
        //value 的父亲结点
        int parent = (child-1) / 2;

        //调整至 child 指向下标为 0 的根结点
        while (child > 0) {
            //比较两者大小
            if (element[child] > element[parent]) {
                swap(child, parent);
                //交换后,child 指向 parent,parent 指向 child 父结点
                child = parent;
                parent = (child-1) / 2;
            } else {
                break;
            }
        }
    }

2.4 堆的删除

核心:将堆顶结点与最后一个结点交换,usedSize-- 实现出堆操作,最后向下调整为大根堆。

    //出堆
    public int poll() {
        //判空
        if (isEmpty()) {
            throw new EmptyException("堆为空!");
        }
        //记录堆顶元素
        int old = element[0];
        //堆顶结点与最后一个结点交换
        swap(0, usedSize-1);
        //删除原堆顶元素
        usedSize--;
        //出堆后开始向下调整为大根堆
        siftDown(0, usedSize);
        //返回堆顶元素
        return old;
    }

    private boolean isEmpty() {
        return usedSize == 0;
    }

2.5 堆排序

① 创建大根堆,初始化 end = userSzie-1,即 end 指向最后一个结点;

② 将栈顶元素交换至 end 下标。由于大根堆中栈顶元素最大,故交换一次,end--,保证每次交换后的栈顶元素位置不变;

③ 重新向下调整为大根堆;

④ 重复 ②、③ 操作,直至排序完成。

    //堆排序
    public void heapSort() {
        int end = usedSize-1;
        while (end > 0) {
            //将大根堆中栈顶元素交换至 end
            swap(0, end);
            //向下调整为大根堆
            siftDown(0, end);
            //保证每次调整的栈顶元素位置不变
            end--;
        }
    }

总结

1、优先级队列出队顺序与入队顺序无关,而与优先级相关。

2、堆将所有元素按完全二叉树的顺序存储方式存储在数组中。

3、堆分为大根堆和小根堆。

4、PriorityQueue 中放置的元素必须能够比较大小、不能插入 null 对象、没有容量限制。

5、PriorityQueue 默认情况下是小根堆,大根堆需要自行提供比较器。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unet已死,Transformer当立!详细解读基于DiT的开源视频生成大模型EasyAnimate

Diffusion Models视频生成-博客汇总 前言&#xff1a;最近阿里云PIA团队开源了基于Diffusion Transformer结构的视频生成模型EasyAnimate&#xff0c;并且提出了专门针对视频的slice VAE&#xff0c;对于目前基于Unet结构的视频生成最好如SVD形成了降维打击&#xff0c;不论是生…

16s功能注释--PICRUST2的安装及使用

文章目录 安装本地安装conda安装 使用一些报错 安装 本地安装 在github网址下载压缩包&#xff1a;https://github.com/picrust/picrust2/releases/tag/v2.5.2 解压后将bin目录设置到环境变量 conda安装 利用bioconda安装 conda create -n picrust2 -c bioconda -c conda-…

Matlab基础语法:变量和数据类型,基本运算,矩阵和向量,常用函数,脚本文件

目录 一、变量和数据类型 二、基本运算 三、矩阵和向量 四、常用函数 五、脚本文件 六、总结 一、变量和数据类型 Matlab 支持多种数据类型&#xff0c;包括数值类型、字符类型和逻辑类型。掌握这些基本的变量和数据类型&#xff0c;是我们进行数学建模和计算的基础。 数…

网络安全复习笔记

概述 要素 CIA&#xff1a;可用性&#xff1b;完整性&#xff1b;保密性。 可控性&#xff1b;不可否认性&#xff1b;可审查性。 攻击 被动&#xff1a;窃听 - 保密性&#xff1b;监听 - 保密性主动&#xff1a;假冒 - 完整性&#xff1b;重放 - 完整性&#xff1b;改写 -…

数学建模系列(4/4):Matlab建模实战

目录 引言 1. Matlab简介与安装 1.1 Matlab简介 1.2 Matlab的安装 2. Matlab基础操作 2.1 Matlab基础语法和常用命令 2.2 Matlab中的数据类型和数据结构 3. 用Matlab进行建模 3.1 矩阵运算与线性代数 矩阵运算 3.2 Matlab中的绘图功能 绘制2D图形 绘制3D图形 3.3…

中服云产品远程运维系统

中服云产品远程运维系统主要针对设备售后市场服务的管理&#xff0c;利用工业物联网技术&#xff0c;一方面面向设备生产厂商&#xff0c;将分散的经销商、客户、销售出去的设备统一管理&#xff1b;另一方面面向设备使用厂家&#xff0c;实现设备实时运行监控&#xff1b;系统…

【手机号性别查询、姓名查询、年龄查询、要素核验接口】支持高并发查询。

** 最近更新时间&#xff1a;2024-06-21 用户手机号注册实名认证接口&#xff0c;精度高&#xff0c;简化注册用户的认证流程&#xff0c;输入手机号码就可以获得认证结果&#xff0c;适合金融、社交、教育、电商、商户入驻等业务场景&#xff0c;用于简化实名认证流程&#…

AI网络爬虫:用deepseek提取百度文心一言的智能体数据

真实网址&#xff1a;https://agents.baidu.com/lingjing/experhub/search/list?pageSize36&pageNo1&tagId-99 返回的json数据&#xff1a;{ "errno": 0, "msg": "success", "data": { "total": 36, "p…

Ollma本地大模型沉浸式翻译【403报错解决】

最终效果 通过Chrome的 沉浸式翻译 插件&#xff0c;用OpenAI通用接口调用本地的Ollma上的模型&#xff0c;实现本地的大模型翻译文献。 官方文档指导的Ollama的配置&#xff1a;一定要配置环境变量&#xff0c;否则会出现【403报错】

H6901B 2.7-24V36V60V72V80V100V 高效率高精度升压型大功率LED恒流驱动芯片

H6901B是一款高效率高精度升压型大功率LED恒流驱动芯片&#xff0c;它具备多种特性和优势&#xff0c;应用于多种LED照明产品中。 首先&#xff0c;H6901B具有宽范围的输入电压&#xff0c;从2.7V到100V&#xff0c;这使其能够适应不同电压源的应用场景。同时&#xff0c;其高效…

【解决方案】智慧园区解决方案(配套源码)

智慧园区整体解决方案-综合运营管理系统 1. 园区现状与发展机遇 2. 智慧园区愿景 3. 智慧解决方案架构 4. 智慧园区各子系统介绍 5. 智慧园区建设意义 楼宇管理&#xff0c;物业管理&#xff0c;消防管理&#xff0c;巡检管理&#xff0c;门禁管理&#xff0c;停车管理等综合实…

如何手机录屏?2个方法轻松搞定!

随着智能手机的普及和移动互联网的飞速发展&#xff0c;手机录屏已经成为人们在日常生活中经常需要使用的功能。无论是录制游戏精彩瞬间、分享App操作教程&#xff0c;还是保留重要聊天信息&#xff0c;手机录屏都发挥着重要作用。可是你知道如何手机录屏吗&#xff1f;本文将介…

若电路板上的二极管损坏后怎么确定型号呢?

若电路板上的二极管损坏后&#xff0c;还可以看清原来管子的型号&#xff0c;换用一个同型号的二极管即可。若看不清型号或管子未标注型号&#xff0c;一般可以根据该二极管在电路中的作用来代换。电路板上的二极管坏了&#xff0c;如何确定它的型号&#xff1f;。 一般来说看…

Linux 软链接

# 语法 ln -s <文件夹or文件的真实路径> <自定义路径别名> # 例子 ln -s /etc/sysconfig/network-scripts/ifcfg-ens33 ~/ens33

【启明智显产品介绍】Model3C工业级HMI芯片详解专题(一)芯片性能

【启明智显产品介绍】工业级HMI芯片Model3C详解&#xff08;一&#xff09;芯片性能 Model3C 是一款基于 RISC-V 的高性能、国产自主、工业级高清显示与智能控制 MCU&#xff0c;配置平头哥E907&#xff0c;主频400MHz&#xff0c;强大的 2D 图形加速处理器、PNG/JPEG 解码引擎…

AI写作如何助力大学生完成毕业论文?

近年来&#xff0c;随着科技的快速发展&#xff0c;AI已经逐渐渗透到了生活中的方方面面&#xff0c;其中也包含着学术领域。 作为学生党&#xff0c;你是否还在为期末论文&#xff0c;大学生实践报告而发愁&#xff1f; 有了这些AI写作神器&#xff0c;大学生们再也不用在期…

Numpy: np.memmap详细用法

文章目录 0. 引言1. 基本用法2. 参数说明3. 例子3.1 读取内存映射文件3.2 修改内存映射文件 4. 使用场景5. 注意事项 0. 引言 np.memmap 是 NumPy 提供的一种用于内存映射大文件的类&#xff0c;允许大文件不完全加载到内存中&#xff0c;而是通过内存映射的方式部分加载。这在…

还原试卷的软件叫什么?这3款一键还原

还原试卷的软件叫什么&#xff1f;在数字化学习日益普及的今天&#xff0c;学生们在处理试卷时经常面临一个问题&#xff1a;如何高效地将已作答的试卷还原成空白状态以便重复练习&#xff1f;为了解决这一问题&#xff0c;市场上涌现出了多款还原试卷的软件。下面&#xff0c;…

职工管理系统

需求分析 系统需要能够实现对职工信息的插入、删除、查找、修改和排序功能。职工信息包括职工编号、姓名、性别、出生年月、参加工作年月、学历、职务、住址、电话等信息。界面友好&#xff0c;通过菜单实现以上功能&#xff0c;操作简单&#xff0c;能够方便快捷地进行信息管理…

RAG实操教程langchain+Milvus向量数据库创建你的本地知识库 二

Miluvs 向量数据库 关于 Milvui 可以参考我的前两篇文章 • 一篇文章带你学会向量数据库Milvus&#xff08;一&#xff09;[1]• 一篇文章带你学会向量数据库Milvus&#xff08;二&#xff09;[2] 下面我们安装 pymilvus 库 pip install --upgrade --quiet pymilvus如果你…