优先级队列
程序员文章站
2024-02-14 14:13:04
...
1.通过优先级比较出队列,比如,手机玩游戏时,如果有电话打进来,那么系统先处理打进来的电话
2.java集合框架提供了两种类型的优先级队列,分别是:priorityqueue(非线程安全)和priorityblockingqueue(线程安全)
3.注意:
- priorityqueue中放置的元素必须要能够进行比大小,不能插入无法比较大小的对象,否则抛异常(ClassCastException异常)
- 不能插入null对象,否则会抛空指针异常
- 没有容量限制,可以插任意多个元素, 其内部可以自动扩容
- 插入和删除元素的时间复杂度为O(log2^N)
- 底层使用了堆这种数据结构
4.优先级队列的构造
1.PriorityQueue()
创建了空的优先级队列,默认容量是11
2. PriorityQueue(int 初始容量)
创建带有初始容量的优先级队列,初始容量不能小于11,否则抛异常
3.PriorityQueue(Collection<? extends E> c)
用一个集合来创建优先级队列
static void TestPriorityQueue(){
// 创建一个空的优先级队列,底层默认容量是11
PriorityQueue<Integer> q1 = new PriorityQueue<>();
// 创建一个空的优先级队列,底层的容量为initialCapacity
PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
ArrayList<Integer> list = new ArrayList<>();
list.add(4);
list.add(3);
list.add(2);
list.add(1);
// 用ArrayList对象来构造一个优先级队列的对象
// q3中已经包含了三个元素
PriorityQueue<Integer> q3 = new PriorityQueue<>(list);
System.out.println(q3.size());
System.out.println(q3.peek());
}
4.优先级队列扩容的规则:
- 如果容量小于64时,是按照oldCapacity*2 + 2的方式扩容的
- 如果容量大于等于64,是按照oldCapacity*2的方式扩容的
- 如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容
实现:
package queue;
import java.util.Arrays;
interface Compare{
public int compare(int left,int right);
}
class Less implements Compare{
//0:left==right
//>0:left>right
//<0:left<right
public int compare(int left, int right){
return left-right;
}
}
class Greater implements Compare{
public int compare(int left, int right){
return right-left;
}
}
//实现小堆
public class MyPriorityQueue {
private int[] array;//存放数据
private int size = 0;//优先级队列中有效元素的个数
private Compare compare=null;
/*public MyPriorityQueue(Compare comp) {
//默认的构造,将其底层默认容量设置为11
array = new int[11];
size = 0;
compare=comp;
}*/
/*public MyPriorityQueue(int initCapacity,Compare comp) {
if (initCapacity < 1) {
//标准库:抛出非法参数的异常
//这里设置为11
initCapacity = 11;
}
array = new int[initCapacity];
size = 0;
compare=comp;
}*/
//标准库中没有该接口--标准库中可以采用集合来构造优先级队列
public MyPriorityQueue(int[] arr,Compare comp) {
array = new int[arr.length];
/*for (int i = 0; i < arr.length; i++) {
array[i] = arr[i];
}*/
System.arraycopy(arr,0,array,0,arr.length);
size = array.length;
//将array中的元素进行调整,满足堆的特性
//找到倒数第一个非叶子节点
compare=comp;
int lastLeaf = (array.length - 2) >> 1;
for (int root = lastLeaf; root >= 0; root--) {
shiftDown(root);
}
}
//获取堆顶元素
public int peek() {
//标准库中,如果优先级队列是空,无法返回堆顶元素,返回null
return array[0];
}
//获取优先级队列有效元素个数
private int size() {
return size;
}
//清空
private void clear() {
size = 0;
}
//插入
private void offer(int x) {
//插入元素之前需要判断是否需要扩容
grow();
array[size++] = x;
shiftUp(size - 1);//注意:此处一定不能使用size--
}
//删除最小元素,堆顶元素
int poll() {
int ret = array[0];
swap(0, size - 1);
size--;
shiftDown(0);
return ret;
}
//判空
boolean isEmpty() {
return size == 0;
}
//只是模拟优先级队列扩容的一部分
private void grow() {
if (size >= array.length) {
int oldCapacity = array.length;
//扩容方式:原容量<64的:原容量的二倍加二,否则:原容量的1.5倍进行扩容
int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));
array = Arrays.copyOf(array, newCapacity);//拷贝
}
}
//调整的方法
//调整以parent为根的二叉树,调整之前一定要保证左右子树已经满足小堆的性质
//不满足就交换,交换后可能导致子树不满足堆的性质,继续调整子树
public void shiftDown(int parent) {
//如果要检测parent是否满足小堆的性质,只需要和孩子比较
int child = parent * 2 + 1;//child标记较小的孩子,parent可能有左没有右孩子
while (child < size) {
//找parent左右孩子中较小的孩子
// if(child + 1 < size && array[child + 1] < array[child]) {//保证右孩子存在,while循环条件已经保证左孩子存在
if (child+1<size&&compare.compare(array[child+1],array[child])<0){
child += 1;
}
//检测parent与较小孩子的大小
//if (array[child] < array[parent]) {
if (compare.compare(array[child],array[parent])<0){
//不满足小堆性质
swap(parent, child);
//交换后可能破坏子树结构
parent = child;
child = parent * 2 + 1;
} else {
//满足
return;
}
}
}
//向上调整
public void shiftUp(int child) {
int parent = (child - 1) >> 1;
while (child != 0) {//或者parent
//if (array[child] < array[parent]) {
if (compare.compare(array[child],array[parent])<0){
swap(parent, child);
child = parent;
parent = (child - 1) >> 1;
} else {
return;
}
}
}
//交换
private void swap(int parent, int child) {
int temp = array[parent];
array[parent] = array[child];
array[child] = temp;
}
public static void main(String[] args) {
int[] array = {5, 3, 7, 1, 4, 6, 8, 0, 2};
MyPriorityQueue mp = new MyPriorityQueue(array,new Greater());
mp.offer(9);
System.out.println(mp.peek());
mp.offer(-1);
System.out.println(mp.peek());
System.out.println(mp.size());
if (mp.isEmpty()){
System.out.println("空");
}else {
System.out.println("非空");
}
while (!mp.isEmpty()){
int temp=mp.poll();
System.out.print(temp+" ");
}
}
}
上一篇: 可以提取表的结构信息