优先级队列 2
1、常用接口介绍
1.1 PriorityQueue的特性

关于PriorityQueue的使用要注意:
1. 使用时必须导入PriorityQueue所在的包,即:
2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常,如下图:
3. 不能插入null对象,否则会抛出NullPointerException。
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容。
5.插入和删除元素的时间复杂度为O(log2N)。
6.底层使用的是堆结构。
7.其默认情况下是小根堆 --> 即每次获得到的元素第是最小的元素。
1.2 PriorityQueue常用接口介绍
1.2.1 优先级队列的构造
在IDEA中的PriorityQueue的Structure中可以看到PriorityQueue有多种构造方法。
这里先做了解,后面会详细讲解。
总结:
注意:默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较。
class IntCmp implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
}
public class Test {
//找第k大的元素就是小根堆的堆的堆顶元素
//找第k小就是大根堆的堆顶元素
public static void main(String[] args) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntCmp());
priorityQueue.offer(12);
priorityQueue.offer(23);
priorityQueue.offer(34);
priorityQueue.offer(45);
System.out.println(priorityQueue);
}
}
1.2.2 插入/删除/获取优先级最高的元素
下图是方法名和使用方法:
优先级队列的扩容:
1.2.3 面试题 17.14. 最小K个数 - 力扣(LeetCode)
Top-k问题:求当前数据中最大或者最小的k个数据,一般来说数据量都比较大。比如:学校的前3名、全球富豪排行榜前100名、世界500强企业.......
做法1:把数组排序 排序之后 去除前10个最大的。但是当数据量非常大的时候,你无法在内存中进行排序。
做法2:把所有数据放到优先级队列中,出队k次就ok了。但是当数据量非常大的时候,你无法放到优先级队列中。
class Solution {
public int[] smallestK(int[] arr, int k) {
int[] ret = new int[k];
if(arr == null || k <= 0){
return ret;
}
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(arr.length);
for (int i = 0; i < arr.length; i++) {
priorityQueue.offer(arr[i]);
}
for (int i = 0; i < k; i++) {
ret[i] = priorityQueue.poll();
}
return ret;
我们建议的做法:
假设找前K个最大的数据,用前K个元素建小根堆K(堆顶就是这K个元素里面的最小值了) 建一个i下标遍历剩余数组,如果i下标的元素大于堆顶元素,那么说明堆顶元素一定不是前K个最大的元素之一 ,把剩下的元素每次与堆顶元素比较,把堆顶元素出队,再把i下标的元素入队。(找前K个最小的数据,则与上面相反要建立大根堆)。
上面OJ链接的代码:(因为是建立大根堆,所以需要创建一个比较器)
class ICompare implements Comparator<Integer>{
public int compare(Integer o1,Integer o2){
return o2.compareTo(o1);
}
}
class Solution {
public int[] smallestK(int[] arr, int k) {
int[] ret = new int[k];
//如果不判断,后面优先级队列会产生空指针异常
if(k==0){
return ret;
}
PriorityQueue<Integer> priorityqueue = new PriorityQueue<>(new ICompare());
//先将K个元素放入优先级队列中
for(int i = 0;i < k;i++){
priorityqueue.offer(arr[i]);
}
//将k后面的元素和 堆顶元素比较
for(int i = k; i < arr.length;i++){
if(arr[i] < priorityqueue.peek()){//说明当前堆顶的元素不是最小的k个数
priorityqueue.poll();
priorityqueue.offer(arr[i]);
}
}
//出k个元素
for(int i = 0;i < k; i++){
ret[i] = priorityqueue.poll();
}
return ret;
}
}
下面是找到最大K个数的代码,可供大家参考:
public static int[] maxestK(int[] arr, int k) {
int[] ret = new int[k];
if(arr == null || k <= 0){
return ret;
}
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(arr.length);
//先放k个元素进小根堆
for (int i = 0; i < k; i++) {
priorityQueue.offer(arr[i]);
}
//遍历剩下的元素
for (int i = k; i < arr.length; i++) {
int top = priorityQueue.peek();
if(arr[i] > top){
priorityQueue.poll();
priorityQueue.offer(arr[i]);
}
}
for (int i = 0; i < k; i++) {
ret[i] = priorityQueue.poll();
}
return ret;
}