java中PriorityQueue优先队列
优先队列 :底层是用数组实现的二叉堆,因为堆通常分为大顶堆或者小顶堆,所以优先队列可以获取每次出来的都是最大或者最小元素(对象可以实现比较器,Java优先级队列默认每次取出来的为最小元素)。
因为底层实现是数据结构堆,所以其时间复杂度peek和element操作的时间复杂度都为常数,
add、offer、remove以及poll的时间复杂度是log(n)。
底层原理:
优先队列底层实际是用数组实现的二叉堆
优先级队列表示为一个平衡的二进制堆:队列[n]的两个子队列是队列[2n+1]和队列[2(n+1)]。优先级队列根据比较器排序,或者如果比较器为空,则根据元素的自然顺序排序:
对于堆的实现是基于数组来实现的,实际开辟存储空间是数组,对数据的访问按照二叉树来进行访问遍历。父节点和子节点编号存在联系,父节点和子节点存在如下关系:
Arr[(i-1)/2] Returns the parent node
Arr[(2i)+1] Returns the left child node
Arr[(2i)+2] Returns the right child node
以小根堆为例,数据如何进行调整:
插入数据
入数据首先在有效数据的最后一个位置,即插入在某个叶子节点上,以该节点为待调整节点,和其父节点比较,如果当前节点大于父节点,符合小根堆,不用进行调整,否则需要进行调整,调整至0号根节点或者是其中某一个位置时当前节点大于父节点才终止。
源码:
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
@SuppressWarnings("unchecked")
private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = key;
}
删除数据
因为是小根堆,其堆顶元素最小,所以删除的为堆顶的元素。删除堆顶元素过程,首先记录0号下标的位置,并用最后一个元素替换0号下标的元素,当前的小根堆可能被破坏,需要对堆进行调整,从k指定的位置开始,将逐层向下与当前的左右孩子中较小的进行交换,直到x小于或者等于左右孩子中的任何一个为止。
源码
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
E result = (E) queue[0];
E x = (E) queue[s];
queue[s] = null;
if (s != 0)
siftDown(0, x);
return result;
}
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
@SuppressWarnings("unchecked")
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
int half = size >>> 1; // loop while a non-leaf
while (k < half) {
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child];
int right = child + 1;
if (right < size &&
((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
if (key.compareTo((E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = key;
}
应用
集合排序
```java
package com.example.demo.suanfa.binary.heap;
import java.util.PriorityQueue;
import java.util.Queue;
public class HeapTest {
public static void main(String[] args) {
Queue<Integer> queue = new PriorityQueue<>();
queue.add(2);
queue.add(10);
queue.add(1);
queue.add(5);
queue.add(7);
queue.add(8);
System.out.print(queue.remove()+" ");
System.out.print(queue.remove()+" ");
System.out.print(queue.remove()+" ");
System.out.print(queue.remove()+" ");
System.out.print(queue.remove()+" ");
System.out.print(queue.remove()+" ");
}
}
执行返回
1 2 5 7 8 10
Process finished with exit code 0
不可以加入null,因为无法比较,所有需要去除null

2.对象加入priorityQueue,需要有属性可以比较,并且实现比较接口Comparable,可实现从小到大排序和从大到小排序
```java
package com.example.demo.suanfa.binary.heap;
import org.springframework.cache.annotation.Cacheable;
public class Student implements Comparable {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Object o) {
Student o1 = (Student) o;
return this.age-o1.age;
}
}
package com.example.demo.suanfa.binary.heap;
import java.util.PriorityQueue;
import java.util.Queue;
public class HeapTest {
public static void main(String[] args) {
Queue<Student> qStudent = new PriorityQueue<>();
qStudent.offer(new Student(3,"小明"));
qStudent.offer(new Student(2,"小红"));
qStudent.offer(new Student(1,"小蓝"));
System.out.println(qStudent.remove().getAge()+" " );
System.out.println(qStudent.remove().getAge()+" " );
System.out.println(qStudent.remove().getAge()+" " );
}
}
执行返回 1 2 3
如果没有实现compare接口 报错