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

news/2024/11/23 1:54:55/

文章目录

  • 1.优先级队列
    • 1.1概念
  • 2.优先级队列的模拟实现
    • 2.1堆的存储方式
    • 2.2堆的创建
    • 2.3建堆的复杂度
    • 2.4堆的插入和删除
  • 3.常用接口介绍

1.优先级队列

1.1概念

队列是一种先进先出的数据结构。但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的的元素先出队列。这种情况下,数据结构提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象,这种数据结构称之为优先级队列(Priority Queue)

2.优先级队列的模拟实现

JDK1.8中的PriorityQueue底层使用了堆的数据结构,而堆实际就是在完全二叉树的基础之上进行了一些元素的调整。
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
在这里插入图片描述

2.1堆的存储方式

堆是一颗完全二叉树,因此可以层序的规则采用顺序的方式来高效存储。
在这里插入图片描述
注意:对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。
将元素存储到数组中后,可以根据二叉树章节的性质5对树进行还原。假设i为节点在数组中的下标,则有:

  • 如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2
  • 如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子
  • 如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子

2.2堆的创建

在这里插入图片描述
在这里插入图片描述

public class TestHeap {public int[] elem;public int usedSize;//有效的数据个数public static final int DEFAULT_SIZE = 10;public TestHeap() {elem = new int[DEFAULT_SIZE];}public void initElem(int[] array){for(int i = 0;i < elem.length;i++){elem[i] = array[i];usedSize++;}}public void createHeap(){for(int parent = ((usedSize-1)-1)/2;parent >= 0;parent--){shiftdown(parent,usedSize);}}//parent:表示每棵子树的节点//len表示没课字数调整的结束位置,不能大于lenpublic void shiftdown(int parent,int len){int  child= parent * 2 +1;//孩子的下标必须小于有效长度,保证有左孩子while(child < len){//child+1 < len保证有右孩子if(child+1 < len && elem[child] < elem[child +1]){child ++;}if(elem[child]>elem[parent]){int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;parent = child;child = 2 *parent + 1;}else{break;}}}
}

在这里插入图片描述
在这里插入图片描述
这是大堆的情况下。那么我们如何改为小根堆呢?很简单,只需要改变两个符号。
在这里插入图片描述
在这里插入图片描述

2.3建堆的复杂度

在这里插入图片描述
综上:建堆的时间复杂度为O(n)

2.4堆的插入和删除

想要向堆中插入元素,我们可以先插入到最后一个位置上。在对其进行大根堆调整。

public void offer(int val){//如果满了就扩容if(isFull()){elem = Arrays.copyOf(this.elem,2*this.elem.length);}elem[usedSize] = val;usedSize++;//调整为大根堆shiftup(usedSize-1);}public void shiftup(int child){int parent = (child-1)/2;while(parent >= 0){if(elem[child] > elem[parent]){int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;child = parent;parent = (child -1)/2;}else{break;}}}public boolean isFull(){return usedSize == elem.length;}

在这里插入图片描述

在这里插入图片描述
其次,我们来看堆的删除:
堆的删除一定删除的是堆顶元素。(删除中间元素无意义)
在这里插入图片描述

public int pop(){if(isEmpty()){throw new isEmptyExpection("堆空异常!");}int tmp = elem[0];elem[0] = elem[usedSize-1];elem[usedSize-1] = tmp;usedSize--;shiftdown(0,usedSize);return tmp;}public boolean isEmpty(){return usedSize == 0;}

3.常用接口介绍

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的。
在这里插入图片描述

关于PriorityQueue的使用要注意:

  1. 使用时必须导入PriorityQueue所在的包,即:
  2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常
  3. 不能插入null对象,否则会抛出NullPointerException
  4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
  5. 插入和删除元素的时间复杂度为
  6. PriorityQueue底层使用了堆数据结构
  7. PriorityQueue默认情况下是小堆—即每次获取到的元素都是最小的元素
    import java.util.PriorityQueue;
    在这里插入图片描述

在这里插入图片描述
默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较器;
在这里插入图片描述
在这里插入图片描述
优先级队列的扩容说明:

  1. 如果容量小于64时,是按照oldCapacity的2倍方式扩容的
  2. 如果容量大于等于64,是按照oldCapacity的1.5倍方式扩容的
  3. 如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

http://www.ppmy.cn/news/12135.html

相关文章

乐鑫 2022 提前批面试题

一面 自我介绍在这简历的四个项目中你最熟悉哪一个?整体介绍一下,画整体框图。在这个项目中你主要负责哪个部分?详细讲一下接收到图像数据之后你的算法工作。为什么帧数选取是 512 帧?为什么选用两种方法进行估计?系统的精确度?你觉得在什么样的情况下输出的准确度会降低…

redis基本数据结构使用与场景

string&#xff08;字符串&#xff09;用法使用场景list&#xff08;列表&#xff09;用法使用场景set&#xff08;不可重复&#xff0c;乱序的集合&#xff09;用法使用场景zset &#xff08;相对于set集合 增加了score属性&#xff0c;score可用于排序&#xff09;用法使用场…

2022年度总结,迎接2023

目录 我和CSDN的2022 初次见面&#xff1a; 你我的成长&#xff1a; 博客&#xff1a; 比赛&#xff1a; 我和CSDN的2023 我和CSDN的2022 初次见面&#xff1a; CSDN你好啊&#xff01;我跟你的初次见面在于2022年4月2日&#xff01;&#xff01;&#xff01; 这这半年内…

redis哨兵模式,自动主备切换,springBoot配置连接

redis哨兵模式&#xff0c;自动主备切换&#xff0c;springBoot配置连接 步骤&#xff08;4个redis实例&#xff0c;为例&#xff09; 安装redis把4个redis实例&#xff0c;配置成一主三从启动4台redis启动redis-sentinel&#xff08;redis自带的哨兵&#xff0c;健康检测&am…

Linux第一个小程序-进度条

目录 \r&&\n 行缓冲区概念 倒计时程序 进度条代码 \r&&\n 回车概念换行概念 \n[rootVM-12-17-centos lesson8]# touch test.c [rootVM-12-17-centos lesson8]# touoch Makefile bash: touoch: command not found [rootVM-12-17-centos lesson8]# touch Mak…

【论文阅读 CIKM2014】Extending Faceted Search to the General Web

文章目录ForewordMotivationMethodQuery facet generation:Facet feedbackEvaluationForeword This paper is from CIKM 2014, so we only consider the insightsI have read this paper last month and today i share this blogThere are many papers that have not been sha…

day03 链表 | 203、移除链表元素 707、设计链表 206、反转链表

题目 203、移除链表元素 删除链表中等于给定值 val 的所有节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#xff1a;head [], val 1 输出&#xff1a;[] 示例 3&#xff1a; 输入&am…

04 链式队列的实现

带头节点的链式队列&#xff1a; 初始化&#xff1a;rear和front指针都指向头节点入队&#xff1a;向rear指向的节点后插入新节点&#xff0c;并让rear指针移动指向新的队尾节点出队&#xff1a;front指针始终指向头节点&#xff0c;即删除头节点后一个节点&#xff1b;最后一个…