前言:优先级队列的实现有很多,PriorityQueue只是其中之一。
1. PriorityQueue
1.1 简介
- Queue接口:该接口规定了只能一头进,另一头出,并没有规定出的逻辑。【注意:java中并没有专门实现先进先出的类,要实现先进先出逻辑,可以使用双端队列Queue】
- PriorityQueue:继承了Queue接口,其继承的是队列的进出操作,该类的出逻辑为优先级最高的出队列。
- 底层结构:PriorityQueue底层采用的堆实现。【堆的相关知识点】
- 安全性:Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列。前者是线程不安全的,后者是线程安全的。
- 细节:
- 优先级导致有序特性,故和 TreeMap[点击查看详情] 一样,在使用PriorityQueue一定要有排序规则:
① 要么 在添加元素时,要添加元素实现了Compareable接口 (比如String、Integer都是从小到大排序)
② 要么 在创建PriorityQueue对象时,传入比较器Comparator。- 不能插入 null 对象,否则会抛出 NullPointerException 异常。
- 进和出的时间复杂度均为 O(log2N)
- 对于remove(Object)和contains(Object)方法是线性时间 O(n)
1.2 构造器
PriorityQueue() | 初始容量(11),自然排序 |
PriorityQueue(Comparator<? super E> comparator) | 初始容量(11),根据比较器排序 |
PriorityQueue(int initialCapacity) | 指定初始容量,自然排序 |
PriorityQueue(int initialCapacity,Comparator comparator) | 指定初始容量,根据比较器排序 |
PriorityQueue(PriorityQueue c) | 创建队列,并复制传入的队列元素,并使用传入的队列的排序方式 |
PriorityQueue(SortedSet c) | 创建队列,并复制传入的SortedSet元素,并使用传入的SortedSet的排序方式 |
1.3 常用方法
错误处理 | 抛出异常 | 返回false、null |
---|---|---|
进 | add(e) | boolean offer(e) |
出并返回删除元素 | remove() | <?> poll() |
查看队首元素 | element() | <?> peek() |
clear() | 清空整个列队 |
---|---|
contains(Object o) | 检查是否包含当前参数元素,返回布尔类型 |
remove(Object o) | 根据value删除指定元素 |
size() | 返回元素个数 |
isEmpty() | 判断队列是否为空,返回布尔类型 |
Object [] toArray() | 将队列中所有元素的放入运行类型为Object的数组中,并返回 |
T[] toArray(T[] a) | 将队列中所有元素的放入传入的数组中,并返回 |
2. 扩容机制
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
int oldCapacity = queue.length;
int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2): (oldCapacity >> 1));
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(minCapacity);
}
queue = Arrays.copyOf(queue,newCapacity);
}
易知,自动扩容机制:
- 如果容量 < 64,按照 oldCapacity * 2 + 2 进行扩容。
- 如果容量 >= 64,按照 oldCapacity * 1.5 进行扩容
- 如果容量超过 MAX_ARRAY_SIZE,按照 MAX_ARRAY_SIZE 进行扩容
3. 关于遍历
PriorityQueue的iterator()不保证由小到大或由大到小输出。若想按大小顺序遍历,可以先将队列转成数组,然后排序遍历。
public static void main(String[] args) {
Queue<Integer> q = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2)
return 1;
else if (o1 == o2) {
return 0;
} else {
return -1;
}
}
});
int[] nums= {2,5,3,4,1,6};
for (int num : nums) {
q.add(num);
}
Integer[] numss = q.toArray(new Integer[nums.length]);
// 从小到大
System.out.println(Arrays.toString(numss));
// 从大到小
Arrays.sort(numss, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(Arrays.toString(numss));
}
输出: