数据结构——优先级队列和堆

news2024/10/10 0:25:00

目录

一、堆

1.概念

2.堆的存储方式

3.性质

4.模拟实现堆(以小根堆为例)

(1).堆的调整

(2).堆的创建

(3).建堆的时间复杂度

(4).堆的插入和删除

5.堆的应用

(1).PriorityQueue的实现

(2).堆排序

(3).Top-k问题

二、优先级队列

1.概念

2.PriorityQueue详解

(1).常用接口 

(2).PriorityQueue的构造方法

(3).常用函数

(4).扩容

(5).注意

三、优先队列(PriorityQueue)和堆(Heap)的区别


一、堆

1.概念

一堆元素集合k={k0,k1...k(n-1)},把所有元素按照完全二叉树的顺序存储方式,存储在一个一维数组中,并且满足ki<=k(2i+1)且ki<=k(2i+2),则称为小堆(反之则为大堆)。
因此在堆的数据结构中,我们将根节点最大的堆称为大根堆或最大堆,将根节点最小的堆称为小根堆或最小堆 。

2.堆的存储方式

堆是一棵完全二叉树,因此可以像层序遍历一样采用顺序存储的方式来存储,更加高效。

注意:对于非完全二叉树则不适合使用顺序存储的方式。在还原二叉树时,空间中需要存储空节点,这会导致空间利用率降低

3.性质

(1).小根堆中某个节点的值总是不小于其父节点的值,大根堆中某个节点的值总是不大于其父节点的值。

(2).堆总是一棵完全二叉树。

4.模拟实现堆(以小根堆为例)

(1).堆的调整

【1】.向下调整

1.让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)

2.如果parent的左孩子存在(child<size),则进行以下操作直到parent的左孩子不存在
    (1).parent右孩子是否存在,存在找到左右孩子中的最小值,让child进行标记
    (2).将parent与较小的孩子child进行比较
        【1】.parent小于较小的孩子child时,结束调整
        【2】.parent大于较小的孩子child时,交换parent与child的值。此时可能并不正确,因此需要继续向下调整,即parent=child;child=parent*2+1;然后重复上述过程

public void shiftDown(int parent,int len){
	int child=2*parent+1;
	while(child<size){
		if(child+1<size&&elem[child+1]<elem[child]){
			child+=1;
		}
		if(elem[parent]<=elem[child]){
			break;
		}else{
			int tmp=elem[parent];
			elem[parent]=elem[child];
			elem[child]=tmp;
			parent=child;
			child=parent*2+1;
		}
	}
}

注意:在整个向下调整的过程中时间复杂度为O (log2N).

【2】.向上调整

1.让child标记需要调整的节点,然后找到child的双亲节点parent。

2.如果双亲节点parent存在(chid>0),则进行以下操作直到双亲节点不存在

    (1).将双亲节点与孩子节点进行交换
        【1】.如果双亲节点比孩子节点小,parent满足堆的性质,调整结束
        【2】.双亲节点大于孩子节点时,交换parent与child的值。此时可能并不正确,因此需要继续向上调整,即child=parent; parent=(child-1)/2; 然后重复上述过程。

public void shiftUp(int child){
	int parent =(child-1)/2;
	while(child>0){
		if(elem[parent]>elem[child]){
			break;
		}else{
			int tmp=elem[parent];
			elem[parent]=elem[child];
			elem[child]=tmp;
			child=parent;
			parent=(child-1)/2;
		}
	}
}

 注意:在整个向上调整的过程中时间复杂度为O (N).

(2).堆的创建

public class Heap{
	public int[] elem;
	public int usedSize;
	public Heap(){
		this.elem=new int[10];
	}
	public void initElem(int[] arr){
		for(int i=0;i<arr.length;i++){
			elem[i]=arr[i];
			usedSize++;
		}
	}
	public void createHeap(){
		for(int parent=(usedSize-1-1)/2;parent>=0;parent--){
			shiftDown(parent,usedSize);
		}
	}
}

(3).建堆的时间复杂度

注意:因为堆是完全二叉树,而满二叉树也是完全二叉树,因此简化为满二叉树来证明。

(4).堆的插入和删除

注意:堆的插入和删除时间复杂度均为O(log2N)

【1】.堆的插入

步骤:
    1.将元素放到最后一个元素后边,空间不够时需要扩容。
    2.将最后新插入的节点向上调整,直到满足要求。

public void push(int val){
	if(isFull()){
		elem=Arrays.copyOf(elem,2*elem.length);
	}
	elem[usedSize++]=val;
	shiftUp(usedSize-1);
}
public boolean isFull(){
    return usedSize==elem.length;
}

【2】.堆的删除

步骤:
    1.将堆顶元素与堆中最后一个元素交换。
    2.将堆中元素有效数据个数减少一个。
    3.对堆顶元素进行向下调整。

public void pop(){
	if(isEmpty()){
		return;
	}
	int tmp=elem[0];
	elem[0]=elem[usedSize-1];
    	elem[usedSize-1]=tmp;
	usedSize--;
	shiftDown(0,usedSize);
}
public boolean isEmpty(){
	return usedSize==0;
}

5.堆的应用

(1).PriorityQueue的实现

用堆作为底层结构封装优先级队列

(2).堆排序

堆排序是利用堆的思想进行排序,首先需要建一个堆,升序排序建大堆,降序排序建小堆;其次利用堆删除思想来进行排序

public void HeapSort(){
	int end=usdSize-1;
	while(end>0){
		swap(elem,0,end);
		shiftDown(0,end);
		end--;
	}
}

(3).Top-k问题

求数据集合中前K个最大的元素或最小的元素,一般情况下数据量比较大,普通排序就不可取,因此我们就需要用到堆来排序。

首先用数据集合中前K个元素建堆(求K个最大元素:建小堆;求K个最小元素:建大堆);然后用剩余的N-K个元素依次与堆顶元素比较,堆顶元素不满足则替换。

二、优先级队列

1.概念

队列是一种先进先出的数据结构,但有时操作的数据会带有优先级,所以在出队列时可能需要优先级较高的的元素先出队列。因此数据结构需要提供:返回最高优先级对象添加新对象这两个基本操作,这种数据结构就是优先级队列。

Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列。PriorityQueue是线程不安全的,而PriorityBlockingQueue是线程安全的,本文重点讲解PriorityQueue。

2.PriorityQueue详解

(1).常用接口 

(2).PriorityQueue的构造方法

【1】.PriorityQueue():创建一个空的优先级队列,默认容量是11

PriorityQueue<Integer> priorityqueue = new PriorityQueue<>();

【2】.PriorityQueue(int initialCapacity):创建一个初始容量为initialCapacity的优先级队列,注意:initialCapacity不能小于1,否则会抛出IllegalArgumentException异常

PriorityQueue<Integer> priorityqueue = new PriorityQueue<>(100);

【3】.PriorityQueue(Collection<?extends E> c) 用一个集合来创建优先级队列

ArrayList<Integer> arraylist = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
PriorityQueue<Integer> priorityqueue = new PriorityQueue<>(arraylist);

(3).常用函数

boolean offer(E e)

插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度 ,注意:空间不够时候会进行扩容。

E peek()

获取优先级最高的元素,如果优先级队列为空,返回null

E poll()

移除优先级最高的元素并返回,如果优先级队列为空,返回null

int size()

获取有效元素的个数

void clear()

清空

boolean isEmpty()

检测优先级队列是否为空,空返回true

(4).扩容

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

(5).注意

【1】.PriorityQueue中放置的元素必须要能比较大小,不能插入无法比较大小的,否则会抛出ClassCastException异常

【2】.不能插入null对象,否则会抛出NullPointerException

【3】.没有容量限制,可以插入任意多个元素,其内部可以自动扩容

【4】.插入和删除元素的时间复杂度为O(log2N)

【5】.PriorityQueue底层使用了堆数据结构

【6】.PriorityQueue默认是小堆,如果需要大堆需要用户提供比较器

// 自定义比较器:直接实现Comparator接口,然后重写该接口中的compare方法即可
class IntCmp implements Comparator<Integer>{
	@Override
	public int compare(Integer o1, Integer o2) {
		return o2-o1;
	}
}

三、优先队列(PriorityQueue)和堆(Heap)的区别

优先队列:是一种特殊的队列

堆:是一个很大的概念并不一定是完全二叉树,在前文中使用完全二叉树是因为这个很容易被数组储存,所以大部分我们用完全二叉树(数组)来储存堆,但是除了这种二叉堆之外我们还有二项堆、 斐波那契堆等这些堆就不属于二叉树。

优先对列和堆有什么区别呢?这里说的堆默认是我们最常使用的二叉堆,而二叉堆只是优先队列的一种是实现方式而已。而优先队列还有二项堆、平衡树、线段树等来实现。所以说优先队列和堆不是一个概念,如果非要说他们之间的关系就是:二叉堆只是优先队列的一种实现方式,而java的PriorityQueue也是基于这个实现的。
 

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

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

相关文章

微服务篇之Eureka注册中心

目录 1. 初识Eureka 1.1 Eureka是什么 1.2 什么是注册中心 1.3 Eureka的原理 2. Eureka的快速入门 2.1 搭建eureka的单机服务 2.2 注册服务的消费者 2.3 注册服务的提供者 3. Eureka的特性 3.1 自我保护机制 3.2 集群支持AP特性 4. Eureka的集群 4.1 不分区集群模式 4.2 分…

Go语言测试(回归测试、集成测试、单元测试简述)与项目开发的流程简述

测试项目流程1. 测试的类别2. 单元测试的规则&#xff08;函数以Test开头&#xff09;2.1 示例12.2 示例23. Mock测试&#xff08;打桩&#xff09;4. 基准测试&#xff08;类似于单元测试&#xff0c;函数以Benchmark开头&#xff09;5. 项目开发的流程项目拆解代码设计测试运…

浪涌保护器(电涌保护器)连接线规格分析方案

低压配电设计中&#xff0c;现在对于浪涌保护器(SPD)及其专用保护装置的标注和画法&#xff0c;都比较规范统一了。那有没有遇到要求标注浪涌保护器连接线规格的情况&#xff1f;或者说&#xff0c;设计师有没有责任要标注清楚各类浪涌保护器连接线规格&#xff1f;地凯科技防雷…

屈光发育档案是什么?为什么专业医生建议从3岁开始就要建立?

当孩子出现近视问题时&#xff0c;家长们都会很焦虑。其实儿童视力发育是一个循序渐进&#xff0c;逐渐成长完善的过程。我们唯一能做的就是预防&#xff0c;在未近视时提前发现近视的趋势。来源&#xff1a;卫生健康委网站这其中最为关键的是建立屈光发育档案。国家青少年近视…

视频剪辑有这6个高清视频素材库就够了

视频剪辑必备的6个网站&#xff0c;免费、可商用&#xff0c;建议收藏&#xff01; 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYxMjky 菜鸟图库网素材类型非常多&#xff0c;平面设计、UI设计、电商类、图片、视频、音频等素材站内都能找到。视频素材全部高清、无…

C++——map和set封装实现

目录 mao和set模拟实现 模拟实现 取K的仿函数 Insert 迭代器 begin和end 和-- operator[] 完整代码 set.h map.h rbtree.h mao和set模拟实现 STL map和set只是包含了几个头文件 主要在选中的这个文件里&#xff0c;打开之后我们可以看到红黑树 用红黑树…

【操作系统】第二章 进程与线程

文章目录第二章 知识体系2.1 进程与线程2.1.1 进程的概念和特征2.1.2 进程的状态与转换2.1.3 进程的组成2.1.4 进程控制2.1.5 进程通信2.1.6 进程的上下文切换2.1.7 线程和多线程模型2.2 处理机调度2.2.1 调度的概念2.2.2 调度的层次分类2.2.3 调度的实现2.2.4 典型的调度算法2…

【八大数据排序法】选择排序法的图形理解和案例实现 | C++

第十五章 选择排序法 目录 第十五章 选择排序法 ●前言 ●认识排序 ●一、选择排序法是什么&#xff1f; 1.简要介绍 2.图形理解 3.算法分析 ●二、案例实现 1.案例一 ● 总结 前言 排序算法是我们在程序设计中经常见到和使用的一种算法&#xff0c;它主要是将一堆不规则…

活体识别3:论文笔记之《FACE ANTI-SPOOFING BASED ON COLOR TEXTURE ANALYSIS》

说明 本文是我对论文《FACE ANTI-SPOOFING BASED ON COLOR TEXTURE ANALYSIS》做的一个简单笔记。 这个论文是芬兰奥卢大学(Oulu)课题组的一篇很有代表性的论文&#xff0c;写于2015年&#xff0c;使用的是“LBP特征SVM分类器”这种比较传统的方案&#xff0c;方案不复杂&…

如何使用 JuiceFS 创建 WebDAV 共享

WebDAV 是一种基于 HTTP 的文件共享协议&#xff0c;最初被设计用于多用户文档协作编辑的场景&#xff0c;也被广泛应用在基于互联网的文件存储、数据同步等网盘类应用场景。 手机端和 PC 端有大量的应用内置了对 WebDAV 的支持&#xff0c;比如知名的文献管理工具 Zotero、iP…

微信小程序 java Springboot校园租房指南房屋租赁系统

东前端&#xff1b;首页、房源信息、租房指南、我的&#xff0c;用户前端&#xff1b;首页、房源信息、租房指南、我的等主要功能模块的操作和管理。 1.出租房源信息的上传、审核、发布&#xff1b; 2.租房信息的浏览、查找、查看&#xff1b; 3.用户与出租方通信&#xff1b; …

Docker-01基本命令

1、Docker安装 系统镜像为Centos7.x yum包更新到最新 sudo yum update安装需要的软件包&#xff0c;yum-util提供yum-config-manager功能。另外两个是devicemapper驱动依赖的 sudo yum install -y yum-utils device-mapper-persistent-data lvm2设置yum源为阿里云 sudo yu…

OpenText 企业内容管理平台客户案例——印度鲁宾(Lupin)制药公司

OpenText 企业内容管理平台客户案例——印度鲁宾&#xff08;Lupin&#xff09;制药公司 公司&#xff1a;Lupin 行业&#xff1a;制药 方案&#xff1a; OpenText™ Extended ECM Platform OpenText™ AppWorks™ OpenText™ Capture 合作伙伴&#xff1a;Muraai Informat…

uniapp数据缓存与apk打包

目录 一、uniapp数据缓存Storage 1.1、存值uni.setStorageSync(KEY,DATA) 1.2、取值uni.getStorageSync(KEY) 1.3、uni.removeStorageSync(KEY) 1.4、uni.clearStorageSync() 二、配置发行H5--打包 一、uniapp数据缓存Storage 1.1、存值uni.setStorageSync(KEY,DATA) 含…

APISIX介绍和安装使用

APISIX目录什么是APISIX&#xff1f;与 Kong的比较概述安装1. 安装依赖2 安装 Apache APISIX2.1 安装脚本2.2 启动 APISIXAPISIX 控制台动态负载均衡1. 启动2个微服务命令2.验证服务是否正常3. 重要概念4.创建 APISIX Upstream&#xff08;上游&#xff0c;后端 API 服务&#…

Python(12)--元组

一、元组的基本介绍 元组&#xff08;tuple&#xff09;&#xff1a;这种数据类型结构与列表相同&#xff0c;但它与列表也有很大的差异&#xff0c;它的元素值与元素个数不可更改。 列表的定义是将元素放入[ ]中&#xff0c;元组的定义是将元素放入&#xff08;&#xff09;中…

通过堆转储快照定位JVM堆内存OOM的问题

目录获取堆转储快照JVM启动时增加参数通过jmap指令生成分析堆转储快照Eclipse Memory Analyzer简介示例获取堆转储快照 如何获取堆转储快照&#xff1f;常用的有两种方式&#xff1a; JVM启动时增加参数 出现OOM时生成堆dump&#xff1a; -XX:HeapDumpOnOutOfMemoryError指…

【2325. 解密消息】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你字符串 key 和 message &#xff0c;分别表示一个加密密钥和一段加密消息。解密 message 的步骤如下&#xff1a; 使用 key 中 26 个英文小写字母第一次出现的顺序作为替换表中的字母 顺序 。将…

【数据结构初阶】第六篇——二叉树的重要性质

树的概念及结构 树的概念 树中专有名词 树的表示 二叉树的概念及其重要性质 二叉树的概念 数据结构中的二叉树 特殊的二叉树 二叉树的性质 二叉树的存储结构 顺序结构 链式结构 树的概念及结构 树的概念 树是一种非线性的数据结构&#xff0c;它是由n(n>0)个有…

【算法】Brute-Force 算法

目录1.概述2.代码实现本文参考&#xff1a; 《数据结构教程》第 5 版 李春葆 主编 1.概述 &#xff08;1&#xff09;设有两个串 s 和 t&#xff0c;串 t 的定位就是要在串 s 中找到一个与 t 相等的子串。通常把 s 称为目标串(target string)&#xff0c;把 t 称为模式串(patt…