最大堆,最小堆,优先队列,堆排序 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

相关文章

在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进程特别设置限制

在Java中实现堆排序的步骤详解

《在Java中实现堆排序的步骤详解》堆排序是一种基于堆数据结构的排序算法,堆是一种特殊的完全二叉树,堆排序利用堆的性质通过一系列操作将数组元素按升序或降序排列,本文给大家介绍了如何在Java中实现堆排... 目录引言一、堆排序的基本原理二、堆排序的实现步骤三、堆排序的时间复杂度和空间复杂度四、堆排序的工作流

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

poj 1734 (floyd求最小环并打印路径)

题意: 求图中的一个最小环,并打印路径。 解析: ans 保存最小环长度。 一直wa,最后终于找到原因,inf开太大爆掉了。。。 虽然0x3f3f3f3f用memset好用,但是还是有局限性。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#incl

hdu 1102 uva 10397(最小生成树prim)

hdu 1102: 题意: 给一个邻接矩阵,给一些村庄间已经修的路,问最小生成树。 解析: 把已经修的路的权值改为0,套个prim()。 注意prim 最外层循坏为n-1。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstri