优先级队列
概念
队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。
在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。
接口
Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,关于PriorityQueue的使用要注意:
- 使用时必须导入PriorityQueue所在的包,即:
import java.util.PriorityQueue;
- PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常,默认情况下:不论怎么调整,0号位置的元素始终是最小的
- 不能插入null对象,否则会抛出NullPointerException
- 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
- 插入和删除元素的时间复杂度为O(logN)
- PriorityQueue底层使用了堆数据结构,
PriorityQueue常用接口介绍:
- List itemPriorityQueue(), 构造一个空的优先级队列:空的优先级队列,但是底层已经有11个默认空间
PriorityQueue<Integer> p1=new PriorityQueue<>();
- PriorityQueue(int initialCapacity),创建一个初始容量为initialCapacity的优先级队列,
注意:
initialCapacity不能小于1,否则会抛IllegalArgumentException异常
如果知道优先级队列中大概要放多少个元素,最好使用该种方式进行构造,不要使用空的构造方式构造,因为在插 入元素时,需要不断扩容而影响程序的效率
PriorityQueue<Integer> p2=new PriorityQueue<>(20);
- PriorityQueue(Collection<? extends E>c),用一个集合来创建优先级队列
List <Integer> s=new ArrayList<>();
s.add(0);
s.add(1);
s.add(2);
PriorityQueue<Integer> p3=new PriorityQueue<>(s);
插入/删除/获取优先级最高的元素
函数名 | 功能介绍 |
boolean offer(E e) | 插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度O(logN),注意:空间不够时候会进行扩容 |
E peek() | 获取优先级最高的元素,如果优先级队列为空,返回null |
int size() | 获取有效元素的个数 |
void clear() | 清空 |
boolean isEmpty() | 检测优先级队列是否为空,空返回true |
经典的TOP-K
设计一个算法,找出数组中最小的个数。以任意顺序返回这K个数。
大家的方式:
1.sort排序:取前K个元素
2.二叉搜索树:按照中序遍历回收K个数据
3.优先级队列:peek,poll
class Solution {
public int[] smallestK(int[] arr, int k) {
// 参数检测
if(null == arr || k <= 0)
return new int[0];
PriorityQueue<Integer> q = new PriorityQueue<>(arr.length);
// 将数组中的元素依次放到堆中
for(int i = 0; i < arr.length; ++i){
q.offer(arr[i]);
}
// 将优先级队列的前k个元素放到数组中
int[] ret = new int[k];
for(int i = 0; i < k; ++i){
ret[i] = q.poll();
}
return ret;
}
}