最大堆,最小堆,优先队列,堆排序 LC例题-找第K大元素

2024-06-05 15:12

本文主要是介绍最大堆,最小堆,优先队列,堆排序 LC例题-找第K大元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LC215 数组中的第K个最大元素

class Solution {static Comparator<Integer> cmp = new Comparator<Integer>(){@Overridepublic int compare(Integer i1, Integer i2){return i1 - i2;//升序排列//  return i2 - i1;//降序}};
public static int findKthLargest(int[] nums, int k) {int len = nums.length;PriorityQueue<Integer> minTop = new PriorityQueue<>(k,cmp);for (int i = 0; i < k; i++){minTop.add(nums[i]);//add 添加元素}for (int i = k; i < len; i++){Integer topEle = minTop.peek();  // 返回队头元素(不删除),失败时前者//peek取出队头元素,不删除// 只要当前遍历的元素比堆顶元素大,堆顶弹出,遍历的元素进去(把最小的元素排出去)if (nums[i] > topEle){minTop.poll();  // 获取队头元素并删除,并返回,失败时前者抛出null,minTop.offer(nums[i]);  // 在队尾插入元素,插入失败时抛出false,并}}return minTop.peek();//(k个里面最小的,就是第k大的)}   
}

定义:

最大堆是一种完全二叉树,其中每个节点的值都大于等于其子节点的值(也就是根节点是最大的),除根节点外每个节点都满足父节点的值大于等于其子节点的堆属性。(大根堆)

最小堆也是一种完全二叉树,其中每个节点的值都小于等于其子节点的值(也就是根节点是最小),除根节点外每个节点都满足父节点的值小于等于其子节点的堆属性。

应用:

堆排序是一种利用堆的数据结构进行排序的算法,nlogn

优先队列:常用于资源调度,任务调度

中位数维护:使用两个堆来维护数据流中的中位数,一个堆最大堆存数据流的前半部分,一个最小堆存数据流后半部分。

最大堆(优先队列)的删除

最大堆的操作先从简单的来,最大堆的设计就是为了方便将最大元素或最小元素以最小的代价给出。

从上面的树中,删除一个最大元素将使得根结点被弹出。需要对根结点经行补全,此时要寻找最大堆中剩余节点中的最大元素补到根结点的位置,也就是数组中下标为1的位置。

很显然,下面的元素中,最大元素必然是根节点的左右子树中较大的那一个。

我们将根节点补充为其较大的那一个儿子。而这个被拿去补充根节点的元素所占的位置仍然需要其较大的子结点去补充,这样不断向下,直到被拿去补充的元素不再拥有左右子树,退出循环。

最大堆(优先队列)的插入

最大的的插入与删除类似于反向操作。

我们首先将要插入的数据放在最大堆的尾部,然后比较其父亲子树与该结点的参数大小,若插入的参数大于其父亲结点的参数,则二者做交换。在不断向上交换的过程中,循环什么时候结束呢?

没错,当比较的元素N/2为0,我们先前定的Flag时,则退出循环,若是最大堆可以将Flag定位无穷大,反之可以定为0或无穷小。

优先队列(Java的PriorityQueue)

PriorityQueue实现了Queue接口,可以存放基本数据类型的包装类或自定义的类(前提是都可排序,必须实现Comparable接口,并根据需要重写CompareTo方法)。

对于基本数据类型的包装类,优先队列中元素默认排列顺序是升序排列。

对于自定义的类,需要定义比较器。

请注意,此实现不同步。 如果任何线程修改队列,多线程不应同时访问PriorityQueue实例。 而是使用线程安全的PriorityBlockingQueue

Comparator<Object> cmp = new Comparator<Object>() {

public int compare(Object o1, Object o2) {

//升序

return o1-o2;

//降序

return o2-o1;

}

};

可以使用以下方法来操作优先队列

insert(key):向优先队列中插入一个元素,时间复杂度为O(logN)。

deleteMin():删除并返回优先队列中优先级最高的元素,时间复杂度为O(logN)。

getMin():返回优先队列中优先级最高的元素,但不进行删除,时间复杂度为O(1)。

add(元素)或offer(元素):向队列中添加元素。

remove()或poll():移除并返回队列中的第一个(最高优先级)元素。

peek():返回队列中的第一个(最高优先级)元素,但不进行移除。

isEmpty():检查队列是否为空。

size():返回队列中的元素个数。

默认情况下,优先队列中的元素按照自然顺序进行排序。但也可以通过传递一个自定义的Comparator对象来指定元素的比较规则。

关于PriorityQueue的使用要注意:

1. 使用时必须导入 PriorityQueue 所在的包,即:

import java.util.PriorityQueue;

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

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

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

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

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

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

默认情况下,PriorityQueue队列是小堆(即队首是最小元素,升序),如果需要大堆需要用户提供比较器

// 用户自己定义的比较器:直接实现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());

}

}

常用方法:

如果容量小于 64 时,是按照 oldCapacity 的 2 倍方式扩容的

如果容量大于等于 64 ,是按照 oldCapacity 的 1.5 倍方式扩容的

如果容量超过 MAX_ARRAY_SIZE ,按照 MAX_ARRAY_SIZE 来进行扩容

优先队列应用

任务调度:在多线程或分布式系统中,任务调度是一个重要的问题。优先队列可以根据任务的优先级来决定执行顺序,高优先级的任务会被首先执行。

搜索算法:在图搜索、最短路径、A*算法等问题中,优先队列可以用来存储待探索的节点,并按照启发式函数的值(估计到目标的距离)进行排序,以便选择下一个最有希望的节点进行探索。

带有时间限制的调度问题:在某些场景下,任务可能有截止时间。优先队列可以根据任务的截止时间来确定执行顺序,确保在截止时间前完成最高优先级的任务。

数据压缩:在哈夫曼编码等数据压缩算法中,优先队列可以用来存储字符及其出现频率,然后构建压缩树。

操作系统调度:操作系统中的进程调度也可以使用优先队列来实现,根据进程的优先级来决定调度顺序。

参考:chatGPT

【Java】PriorityQueue--优先级队列_java priorityqueue-CSDN博客

学习一波Java语言中的优先队列 PriorityQueue_java 优先队列-CSDN博客

Java优先队列PriorityQueue使用详解_java priorityqueue用法-CSDN博客

数据结构学习之——最大堆、最小堆(优先队列、哈夫曼树)_最大堆和最小堆原理-CSDN博客

这篇关于最大堆,最小堆,优先队列,堆排序 LC例题-找第K大元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制