java优先级队列(堆)详解

一、优先级概念

什么是优先级:比如女士优先,个子低的优先排到前面去,有一部分数据具备优先级,要以优先级的顺序将顺序存储起来。

前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列

priorityQueue是二叉树的完全二叉树,只不过是用数组来进行顺序存储

PriorityQueue底层使用了堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整。

二、堆的概念

所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki 且 Ki= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

性质:

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

小根堆:根节点的大小小于孩子节点

大根堆:根节点的大小大于孩子节点

三、堆的存储方式

从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,

完全二叉树:数组的每一个位置被充分使用    

一般二叉树:有的位置被浪费掉没有存储值

所以对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。

四、堆的创建与方法实现

import java.util.Arrays;

public class TestHeap {

    public int[] elem;
    public int usedSize;

    public TestHeap(){
        this.elem = new int[10];
    }
    public void init(int[] array){
       for(int i = 0;i<array.length;i++){
           elem[i] = array[i];
           usedSize++;
       }
    }
    //把elem数组当中的数据 调整为大根堆
    public void createHeap(){
        int size = usedSize;
        for(int parent = (size-1-1)/2;parent>=0;parent--){
            siftDown(parent,size);
        }
    }
    private void swap(int i,int j){
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }
    //每棵子树向下调整  知父亲求孩子
    public void siftDown(int parent,int end){
        int child = 2*parent+1;
        while(child<end){
            if(child+1<end&&elem[child]<elem[child+1]){
                //找到大的             
               child++;
            }
            //chile下标就是左右孩子最大值
            if(elem[child]>elem[parent]){
                swap(child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }

    //调整为小根堆
    public void siftDown2(int parent,int end){
        int child = 2*parent+1;
        while(child<end){
            if(child+1<end&&elem[child]>elem[child+1]){
                //找出最小
                child++;
            }
            //chile下标就是左右孩子最大值
            if(elem[child]<elem[parent]){
                swap(child,parent);
                parent = child;
                child = 2*parent+1;
            }else{
                break;
            }
        }
    }

    //插入
    public void offer(int val){
        if(isFull()){
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
        siftUp(usedSize-1);
    }
    //向上调整成大根堆,知孩子求父亲
    public void siftUp(int child){
        int parent = (child-1)/2;
        while(parent>=0){
            if(elem[child]>elem[parent]){
                swap(child,parent);
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }
    //向上调整复杂度O(N*logN)

    public boolean isFull(){
        return usedSize==elem.length;
    }
    //删除第一个节点 将0下标与最后一个节点交换,再向下调整
    public int poll(){
        if(isEmpty()){
            return -1;
        }
        int old = elem[0];
        swap(0,usedSize-1);
        usedSize--;
        siftDown(0,usedSize);
        return old;
    }
    public boolean isEmpty(){
        return usedSize==0;
    }
    //数组排序,从小往大排,建立大根堆,从大往小排建立小根堆
    public void heapSort(){
        int endIndex = usedSize-1;
        //O(N)
        while(endIndex>0){
            swap(0,endIndex);
            siftDown(0,endIndex);//调整成大根堆O(logN)
            endIndex--;
        }
        //O(N*logN)
    }

}

对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成堆呢?

调整大根堆方法:从整棵树的最后一棵子树开始调整,每次让根节点与左右孩子比较,如果根节点比左右孩子的最大值都小,就交换根节点和孩子最大值。(小根堆同理)

上图就是大根堆

向下调整时间复杂度:约为N

Tn = 2^0*(h-1)+2^1*(h-2)+...+2^(h-2)*1+2^(h-1)*0
2Tn = 2^1*(h-1)+2^2*(h-2)+...+2^(h-1)*1
两式错位相减Tn = -2^0(h-1)+2^1+2^2+.....+2^(h-1)=-h-1+2^h
h = log以2为底(N+1)
Tn = -log(N+1)-1+N+1 = N-log(N+1)
n越来越大Tn约等于N

向上调整时间复杂度为N*logN

五、PriorityQueue常用接口介绍

1、优先级队列的构造(无构造器)

构造器功能介绍
PriorityQueue()创建一个空的优先级队列,默认容量是11
PriorityQueue(int initialCapacity)创建一个初始容量为initialCapacity的优先级队列,注意: initialCapacity不能小于1,否则会抛IllegalArgumentException异 常
PriorityQueue(Collection<? extends E> c)用一个集合来创建优先级队列
    public static void main(String[] args) {
        //堆是队列实现的,叫优先级队列,数组实现
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(12);
        priorityQueue.offer(5);
        priorityQueue.offer(57);
        System.out.println(priorityQueue.peek());//结果是5 所以默认是小根堆,也可以改为大根堆,以后讲
        Queue<Integer> queue = new PriorityQueue<>();
        //PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的
        PriorityBlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();//多线程下推荐使用
    }

2、 功能

函数名功能介绍
boolean offer(E e)插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度,注意:空间不够时候会进行扩容

E peek()

获取优先级最高的元素,如果优先级队列为空,返回null
E poll()移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size()获取有效元素的个数

void clear()

清空
boolean isEmpty()检测优先级队列是否为空,空返回true

offer功能 

 

给比较器 

 未给比较器

  将key强转为Comparable,所以需要实现Comparable接口,未实现就会出现类型转换异常

比如:如果创建student类的堆,如果未实现接口就会抛出异常

compareTo可以实现大堆小堆的转换

比较器

默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较器

提供比较器构造功能介绍
public PriorityQueue(Comparator<? super E> comparator)
可以改为大堆创建
PriorityQueue(int initialCapacity,              Comparator<? super E> comparator)
可以大堆创建初始容量为initialCapacity的优先级队列
class IntCmp implements Comparator<Integer>{
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);//小根堆,如果o1和o2互换就是大根堆
    }
}

注意:

1、使用时必须导入PriorityQueue所在的包

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

3. 不能插入null对象,否则会抛出NullPointerException

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

5. 插入和删除元素的时间复杂度为

6. PriorityQueue底层使用了堆数据结构

7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素  

top-k:最小的k个数 

 public static int[] smallestK(int[] arr,int k){
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        for (int i = 0; i < arr.length; i++) {
            priorityQueue.offer(arr[i]);//时间复杂度NlogN
        }
        int[] tmp = new int[k];
        for (int i = 0;i<k;i++){
            int val = priorityQueue.poll();//时间复杂度k*logN
            tmp[i] = val;
        }
        //整个时间复杂度是(N+k)logN,不是真的top-k的解法
        return tmp;
    }
   

最小的k个数->建立大小为k的大根堆

最大的k个数->建立大小为k的小根堆 

 class IntCmp implements Comparator<Integer>{
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);//大根堆,如果o1和o2互换就是小根堆
    }
}
public static int[] smallestK2(int[] arr,int k){
        int[] tmp = new int[k];
        if(k==0){
            return tmp;
        }
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new IntCmp());//大小为k的大根堆
        for (int i = 0; i < k; i++) {
            maxHeap.offer(arr[i]);//K*logK
        }
        //遍历剩下的元素
        for (int i = k;i<arr.length;i++){
            int val = maxHeap.peek();
            if(val>arr[i]){
                maxHeap.poll();
                maxHeap.offer(arr[i]);
            }
        }//(N-K)*logK
        tmp = new int[k];
        for (int i = 0;i<k;i++){
            tmp[i] = maxHeap.poll();//时间复杂度k*logN
        }
        return tmp;
//时间复杂度N*logK
    }

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

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

相关文章

OceanBase开发者大会2023届视频及PPT汇总

数据库技术趋势 我眼中的数据库技术 阳振坤OceanBase 首席科学家 观看视频 下载 PDF 未来&#xff0c;中国需要什么样的数据库&#xff1f; 周傲英华东师范大学副校长&#xff0c;CCF 会士 观看视频 下载 PDF 云原生技术趋势解读 Keith ChanCNCF 云原生计算基金会中国区总监 …

开发工具的使用

IDEA的安装与使用&常用快捷键 文章目录 IDEA的安装与使用&常用快捷键一、认识IntelliJ IDEA二、IDEA 的下载&卸载三、IEAD相关设置3.1 JDK的相关设置3.2 系统设置&#xff08;启动项/自动更新&#xff09;3.3 设置整体主题&#xff08;主题/字体/背景&#xff09;3…

Linux--链表 第二十五天

1. 链表 t1.next -> data t1.next->next->data .(点号)的优先级比->的大 所以 t1.next->data 就可以了 不用(t1.next)->data 2. 链表的静态增加和动态遍历 打印链表算法&#xff0c; void printLink(struct Test *head) { struct Te…

如何做一个优秀的系统工程师?

一、背景 做好一个优秀系统工程师的关键在于其在产品开发生命周期中对需求分析的有效把握与运用&#xff0c;这个过程直接影响到系统的整体架构设计、规格参数的明确设定以及业务流程的深度挖掘与优化。需求分析不仅是理解用户实际问题的核心环节&#xff0c;更是界定系统开发…

Java基础之JVM对象内存分配机制简介

一 对象内存分配 1.1 运行时数据区域 1.2 常见java应用启动JVM参数&#xff1a; -Xss&#xff1a;每个线程的栈大小(单位kb)-Xms&#xff1a;堆的初始大小&#xff0c;默认物理内存的1/64,示例&#xff1a;-Xms:4g -Xms:10m-Xmx&#xff1a;堆的最大可用大小&#xff0c;默认物…

LeetCode 热题 100 题解:普通数组部分

文章目录 题目一&#xff1a;最大子数组和&#xff08;No. 53&#xff09;题解 题目二&#xff1a;合并区间&#xff08;No. 56&#xff09;题解 题目三&#xff1a;轮转数组&#xff08;No. 189&#xff09;题解 题目四&#xff1a;除自身以外数组的乘积&#xff08;No. 238&a…

springSecurity用户认证和授权

一&#xff0c;框架介绍 Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架&#xff0c;提供了一套 Web 应用安全性的完整解决方案。一般来说&#xff0c;Web 应用的安全性包括用户认证&#xff08;Authentication&#xff09;和用户授权&am…

zig v0.12.0 发布 — x-cmd 提供 zig 快捷安装方法和 x zig 模块

文章目录 简介功能特点v0.12.0 新特性[重新设计 Autodoc 的工作原理](https://ziglang.org/download/0.12.0/release-notes.html#Redesign-How-Autodoc-Works)语法变更各类标准库变更构建系统变更 常见用法**使用案例**:竞品和相关项目进一步阅读 简介 Zig 是一种通用编程语言…

模电期末复习(五)集成运算放大电路

集成运算放大电路 5.1 集成放大电路的特点5.2 集成运放的主要技术指标5.3 集成运放的基本组成部分5.3.1 偏置电路5.3.2 差分放大输入级5.3.3 中间级5.3.4 输出级 5.4 集成运放的典型电路5.4.1 双极型集成运放LM741 5.5 各类集成运放的性能特点5.6 集成运放使用中的几个具体问题…

JAVAEE——IP协议

文章目录 IP协议IP协议报头格式IP协议报头的各个区段四位版本四位首部长度八位服务类型16位总长度16位标识&#xff0c;3位标志&#xff0c;13位片偏移八位生存时间八位协议 地址管理IP地址解决提议1&#xff1a;动态分配Ip地址解决提议2&#xff1a;NAT机制 IP协议 IP协议报头…

基于SpringBoot+Vue钢材销售管理系统的设计与实现

系统介绍 为了更好地发挥本系统的技术优势&#xff0c;根据钢材销售管理系统的需求&#xff0c;本文尝试以B/S经典设计模式中的Spring Boot框架&#xff0c;JAVA语言为基础&#xff0c;通过必要的编码处理、钢材销售管理系统整体框架、功能服务多样化和有效性的高级经验和技术…

分类神经网络3:DenseNet模型复现

目录 DenseNet网络架构 DenseNet部分实现代码 DenseNet网络架构 论文原址&#xff1a;https://arxiv.org/pdf/1608.06993.pdf 稠密连接神经网络&#xff08;DenseNet&#xff09;实质上是ResNet的进阶模型&#xff08;了解ResNet模型请点击&#xff09;&#xff0c;二者均是…

葡萄书--关系图卷积神经网络

异质图和知识图谱 同质图与异质图 同质图指的是图中的节点类型和关系类型都仅有一种 异质图是指图中的节点类型或关系类型多于一种 知识图谱 知识图谱包含实体和实体之间的关系&#xff0c;并以三元组的形式存储&#xff08;<头实体, 关系, 尾实体>&#xff0c;即异…

vlan的学习笔记1

vlan&#xff1a; 1.一般情况下:以下概念意思等同: 一个vlan一个广播域 一个网段 一个子网 2.一般情况下: &#xff08;1&#xff09;相同vlan之间可以直接通信&#xff0c;不同vlan之间不能直接通信! &#xff08;2&#xff09;vlan技术属于二层技术&…

三、Flask模型基础

ORM 创建模型 # exts.py:插件管理 # 扩展的第三方插件 # 1.导入第三方插件 from flask_sqlalchemy import SQLAlchemy # ORM插件 from flask_migrate import Migrate # 2. 初始化 db = SQLAlchemy() # ORM migrate = Migrate() # 数据迁移 # 3. 和app对象绑定 def init_ex…

基于Bootstrap 4的企业项目体验服务网站模板

目录 一.前言 二.展示 三.下载链接 一.前言 网页包含以下内容&#xff1a; 页面基本信息&#xff1a;设置页面的字符集、兼容性、视口等元数据。 网站标题和描述&#xff1a;定义了网站的标题为"Benten"&#xff0c;同时也设置了关键词和描述。 CSS样式表链接&a…

基于SpringBoot+Vue七匹狼商城系统的设计与实现

系统介绍 近年来随着社会科技的不断发展&#xff0c;人们的生活方方面面进入了信息化时代。计算机的普及&#xff0c;使得我们的生活更加丰富多彩&#xff0c;越来越多的人使用通过网络来购买各类的商品。早期商品的销售和购买都是通过实体店&#xff0c;这种购买方式需要耗费…

《苍穹外卖》Day03部分知识点记录

一、公共字段自动填充 业务表中的公共字段&#xff1a; 序号字段名含义数据类型操作类型1create_time创建时间datetimeinsert2create_user创建人idbigint3update_time修改时间datetimeinsert、update4update_user修改人idbigint 问题&#xff1a;代码冗余&#xff0c;不便于…

const成员函数 以及 取地址及const取地址操作符重载

目录 const成员函数 结论&#xff1a; 取地址及const取地址操作符重载 const成员函数 将const 修饰的 “ 成员函数 ” 称之为 const成员函数 &#xff0c; const 修饰类成员函数&#xff0c;实际修饰该成员函数的&#xff08;*this&#xff09; &#xff0c;表明在该成员函数…

ROS2 王牌升级:Fast-DDS 性能直接碾压 zeroMQ 「下」

以下内容为本人的学习笔记&#xff0c;如需要转载&#xff0c;请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/aU1l3HV3a9YnwNtC1mTiOA 性能比较 下面就以官网的测试数据为准&#xff0c;让我们一起来看看它们的性能差别到底怎样。 本次比较仅针对 Fast RT…