知识改变命运 数据结构【优先级队列(堆)】

news2024/12/23 9:12:45

优先级队列(堆)

  • 1:堆概念
  • 2:堆的创建(以小根堆为例)
  • 3:堆的插入与删除
    • 3.1 堆的插入
    • 3.2堆的删除
  • 4:oj练习
  • 5:堆排序
  • 6接口介绍(底层代码的查看)
    • 6.1常用三种构造方法

前言:队列是一种先进先出的数据结构,但是某时候有一些数据有优先级,比如打游戏时候突然来个电话。在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。

1:堆概念

官方:如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
我自己简单认为就是把二叉树修改了一些,修改了存储方式,二叉树是一种链式存储,而堆是一种顺序存储是数组,分为了大根堆和小根堆

堆的一些特征:
1:堆是一颗完全二叉树
2:堆采用的是层序规则顺序存储结构,因为堆是一颗完全二叉树,非完全二叉树不适合顺序存储,会造成空间的浪费
2:堆的子节点的值不大于或者不小于其父亲结点的值
以小根堆为例:
在这里插入图片描述

一些重要的二叉树性质:
在这里插入图片描述

2:堆的创建(以小根堆为例)

问题:对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成堆呢?
我自己理解画的图的和写的代码:
在这里插入图片描述

public class TestHeap {
    public int usedSize;
    public int []elem;
    public TestHeap() {
        this.elem = new int[10];
    }

    public void initElem(int[] array) {
        for (int i = 0; i < array.length; i++) {
            this.elem[i] = array[i];
            usedSize++;
        }
    }
    // 时间复杂度:O(N)
    public void  createHeap() {
        //每个父亲节点
        for (int parent=(usedSize-1-1)/2;parent>=0;parent--) {
            sitfDown(parent,usedSize-1);//调整
        }
    }
 时间复杂度:O(log(n))
    private void sitfDown(int parent, int i) {
        int child=2*parent+1;//先求出左孩子结点
        while(child<=i) { //结束条件child<useSize这里传过来的是usedSize-1
            if ((child+1<=i)&&elem[child]>elem[child+1]) {
                child++;//判断左右孩子的大小,如果左边大,就调整为右孩子结点
            }
            //判断父结点和子结点大小
            if(elem[parent]>elem[child]) {
                swap(elem,parent,child);//如果父节点大于就交换
                //继续往下调整
                parent=child;
                child=2*parent+1;
            }else  {
                //如果父子节点小于子结点之间结束循环,因为是从最后一颗树调整,所有下面的树就是小根堆。
                break;
            }

        }
    }

    private void swap(int array[],int parent, int child) {
        int temp=array[parent];
        array[parent]=array[child];
        array[child]=temp;
    }
}

注意事项:
子结点必须已经是小根堆
在调整以parent为根的二叉树时,必须要满足parent的左子树和右子树已经是堆了才可以向下调整。
这里主要注意一下结束条件,还要就是如果父亲结点比子结点小,直接跳出循环的理解,因为当父亲结点小于子节点时候,子节点本来已经就是小根堆了,父亲结点的值就不可能比子节点的值再小了。

建堆的时间复杂度
因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):
在这里插入图片描述
向上建堆的时间复杂度
在这里插入图片描述

3:堆的插入与删除

3.1 堆的插入

 public void offer(int val) {
        if(isFull()==true) {
            elem= Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize]=val;
        upDown(usedSize,elem);
        usedSize++;
    }

    private void upDown(int usedSize, int[] elem) {
        int parent=(usedSize-1)/2;
        int child=usedSize;
        while(parent>=0) {
            if(elem[child]<elem[parent]) {
                swap(elem,parent,child);
                child=parent;
                parent=(child-1)/2;
            } else {
                break;
            }
        }
    }

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

堆的插入总共需要两个步骤:

  1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
  2. 将最后新插入的节点向上调整,直到满足堆的性质
  3. 在这里插入图片描述

3.2堆的删除

 public void  poll() {
        if (isEmpty()) {
            return;
        }
        swap(elem,0,usedSize-1);
        usedSize--;
        siftDown(0,usedSize-1);//调整

    }

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

注意:堆的删除一定删除的是堆顶元素。具体如下:

  1. 将堆顶元素对堆中最后一个元素交换
  2. 将堆中有效数据个数减少一个
  3. 对堆顶元素进行向下调整
    在这里插入图片描述

4:oj练习

top-k问题:最大或者最小的前k个数据。比如:世界前500强公司
top-k问题:最小的K个数
在这里插入图片描述
优化:
topk方法解决。

 public static int [] findmax(int []array,int k) {
        PriorityQueue<Integer> priorityQueue =new PriorityQueue<>();
        //k*log(K)
        for (int i = 0; i <k ; i++) {
            priorityQueue.offer(array[i]);
        }
        //(n-k)*log(k)
        for (int i = k; i <array.length ; i++) {
            int peek=priorityQueue.peek();
            if(peek<array[i]) {
                priorityQueue.poll();
                priorityQueue.offer(array[i]);
            }
        }
        int []elem=new int[k];
        for (int i = 0; i <k ; i++) {
            elem[i]=priorityQueue.poll();
        }
        return elem;
    }

在这里插入图片描述

5:堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

  1. 建堆
    升序:建大堆
    降序:建小堆
  2. 利用堆删除思想来进行排序
    建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。
    在这里插入图片描述

6接口介绍(底层代码的查看)

PriorityQueue的特性
Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的
在这里插入图片描述
关于PriorityQueue的使用要注意:

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

6.1常用三种构造方法

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在堆里面默认的是小堆,如果我们要建大堆就要设置比较器,给堆传入比较器。

// 用户自己定义的比较器:直接实现Comparator接口,然后重写该接口中的compare方法即可
class IntCmp implements Comparator<Integer>{
@Override
	public int compare(Integer o1, Integer o2) {
		return o2-o1;
	}
}
public class TestPriorityQueue {
	public static void main(String[] args) {
		PriorityQueue<Integer> p = new PriorityQueue<>(new IntCmp());
		p.offer(4);
		p.offer(3);
		p.offer(2);
		p.offer(1);
		p.offer(5);
		System.out.println(p.peek());
	}
}

在这里插入图片描述
我们再了解一下jdk8的扩容机制

   private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    private void grow(int minCapacity) {
        int oldCapacity = queue.length;
// Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                (oldCapacity + 2) :
                (oldCapacity >> 1));
// overflow-conscious code
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

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

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

相关文章

Flutter-->Namespace not specified.

更新Android gradle 7.5.0之后, 运行项目会出现Namespace not specified.问题, 这里出一个我的解决方案. 由于很多库都不可能及时更新适配gradle 7.5.0, 所以可以等pub get将子库拉取到本地之后, 在本地手动添加namespace属性,即可解决本文问题. 作为程序猿,那肯定不可能手动修…

Elasticsearch、Kibana学习

系列文章目录 JavaSE基础知识、数据类型学习万年历项目代码逻辑训练习题代码逻辑训练习题方法、数组学习图书管理系统项目面向对象编程&#xff1a;封装、继承、多态学习封装继承多态习题常用类、包装类、异常处理机制学习集合学习IO流、多线程学习仓库管理系统JavaSE项目员工…

鸿蒙--知乎评论

这里我们将采用组件化的思想进行开发 拆解组件 pages下&#xff0c;新建ZhiHu的文件pages下&#xff0c;新建components, 里面新建 HmNavBar和HmCommentItem components/HmNavBar.ets Entry Component struct HmNavBar {title: string 标题build() {Row() {// 返回键Row() {I…

数据湖数据仓库数据集市数据清理以及DataOps

一提到大数据我们就知道是海量数据&#xff0c;但是我们并不了解需要从哪些维度去考虑这些数据的存储。比如 数据湖、数据仓库、数据集市&#xff0c;以及数据自动化应用DataOps有哪些实现方式和实际应用&#xff0c;这篇文章将浅显的做一次介绍。 数据湖 数据湖是一种以自然…

Spring Boot 学习之路 -- Thymeleaf 模板引擎

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;后端对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门…

Python爬虫之正则表达式于xpath的使用教学及案例

正则表达式 常用的匹配模式 \d # 匹配任意一个数字 \D # 匹配任意一个非数字 \w # 匹配任意一个单词字符&#xff08;数字、字母、下划线&#xff09; \W # 匹配任意一个非单词字符 . # 匹配任意一个字符&#xff08;除了换行符&#xff09; [a-z] # 匹配任意一个小写字母 […

获取淘宝直播间弹幕数据的技术探索实践方法

在数字时代&#xff0c;直播已成为电商营销的重要渠道之一&#xff0c;而弹幕作为直播互动的核心元素&#xff0c;蕴含着丰富的用户行为和情感数据。本文将详细介绍如何获取淘宝直播间弹幕数据的技术方法和步骤&#xff0c;同时分析不同工具和方法的优缺点&#xff0c;并提供实…

夜莺监控的机器支持挂载到多个业务组了

夜莺开源项目于国庆前夕发布了 v7.4.1 版本&#xff0c;修复了一些 bug&#xff0c;同时也带来了一些新功能。其中最重要的一个功能是&#xff1a;机器支持挂载到多个业务组了。本文将介绍几个重要的变更。 所有变更点 feat: 左侧栏业务组新设计feat: 机器支持了绑定到多个业…

GAN(Generative Adversarial Nets)

GAN(Generative Adversarial Nets) 引言 GAN由Ian J. Goodfellow等人提出&#xff0c;是Ian J. Goodfellow的代表作之一&#xff0c;他还出版了大家耳熟能详的花书&#xff08;Deep Learning深度学习&#xff09;&#xff0c;GAN主要的思想是同时训练两个模型&#xff0c;生成…

CentOS 7 安装并部署 Mysql

安装 Mysql 下载并添加库 sudo yum localinstall https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm安装 Mysql 包&#xff08;一路键入y即可&#xff09; yum -y install mysql mysql-server --nogpgcheck- -nogpgcheck 作用为 禁掉GPG验证检查 配…

Serilog文档翻译系列(七) - 应用设置、调试和诊断、开发接收器

01应用设置 Serilog 支持在 App.config 和 Web.config 文件中使用简单的 配置语法&#xff0c;以设置最低日志级别、为事件添加额外属性以及控制日志输出。 Serilog 主要通过代码进行配置&#xff0c;设置支持旨在作为补充功能。虽然不是全面的&#xff0c;但大多数日志记录配…

SpringBoot3实战:实现接口签名验证

有时候我们要把自己的服务暴露给第三方去调用&#xff0c;为了防止接口不被授权访问&#xff0c;我们一般采用接口签名的方式去保护接口。 接下来松哥和大家聊一聊这个话题。 一 场景分析 什么时候需要接口签名&#xff1f; 接口签名是一种重要的安全机制&#xff0c;用于确…

Jmeter链接数据库、分布式

目录 一、Jmeter链接数据库 连接准备 有两种添加驱动的方法 第一种&#xff1a; 第二种&#xff1a; 连接方法&#xff1a; 1.先添加一个配置元件中的jdbc connection configuration 2、配置内容 使用&#xff1a; 二、Jmeter做分布式操作 1、准备多台电脑 2、多台电…

顶象生僻字点选模型识别

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 该文章模型已经上线ocr识别网站,欢迎测试!!,地址:http://yxlocr.nat300.top/ocr/textclick/5 某网站使用顶象的生僻字点选模型,部分数据集如下: 这种数据集…

【Vue3 + TS + Vite】从0到1搭建后台管理系统

前言 没搭建过Vue3的项目&#xff0c;从0开始搭建一下&#xff0c;记录一下自己的步骤。 技术栈&#xff1a; vue3 ts scss pinia vite 我尽量写的详细一些&#xff0c;后续也会记录我在项目过程中&#xff0c;遇到的一些问题。 文章目录 前言环境搭建一、创建项目1. 使用…

使用IOT-Tree Server制作一个边缘计算设备(Arm Linux)

最近实现了一个小项目&#xff0c;现场有多个不同厂家的设备&#xff0c;用户需要对此进行简单的整合&#xff0c;并实现一些联动控制。 我使用了IOT-Tree Server这个软件轻松实现了&#xff0c;不外乎有如下过程&#xff1a; 1&#xff09;使用Modbus协议对接现有设备&#…

探索循环神经网络RNN:解锁序列数据的奥秘

在这个数据驱动的时代&#xff0c;机器学习模型已经深入到我们生活的方方面面&#xff0c;从智能推荐系统到自然语言处理&#xff0c;无一不彰显其强大的能力。在众多模型中&#xff0c;循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;以其独特的结构和对序…

Java日志(总结)

一、logback日志 Logback是由log4j创始人设计的又一个开源日记组件。logback当前分成三个模块&#xff1a;logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J …

elasticsearch创建索引

1对比关系型数据库&#xff0c;创建索引就等同于创建数据库 在postman中&#xff0c;向ES服务器发PUT请求 显示已经创建成功了 http://192.168.1.108:9200/shopping 请求方式get http://192.168.1.108:9200/shopping 请求全部的index的url地址 get 请求 http://192.168.1.10…

OpenHarmony(鸿蒙南向开发)——轻量系统内核(LiteOS-M)【扩展组件】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… C支持 基本概念 C作为目前使用最广泛的编程语言之一&#xff0c;…