一.概念
队列是一种先进先出的数据结构,但有些情况下,操作的数据可能带有优先级,出队列时可能需要优先级高的元素先出队列。数据结构提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列
二.优先级队列的模拟实现
PriorityQueue底层使用了堆这种数据结构,而堆实际上就是在完全二叉树的基础上进行了一些调整
1.堆的概念
如果有一个关键码的集合K={k0, k1, k2 ,... ,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储,在一个一维数组中,并满足:ki <= k2i+1 且 ki <= k2i+2 (ki >= k2i+1 且 ki>= k2i+2)i=0, 1 ,2...,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
堆的性质:
- 堆中某个节点的值总是不大于或不小于其父亲节点的值;
- 堆总是一棵完全二叉树
2.堆的存储方式
堆是一棵完全二叉树,可以层序的规则采用顺序的方式来高效存储
注意:对于非完全二叉树,不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低
3.堆的创建
import java.util.Arrays;
public class TestHeap {
private int[] elem;
private int usedSize;
public TestHeap() {
this.elem = new int[10];
}
public void initHeap(int[] array) {
for (int i = 0; i < array.length; i++) {
elem[i] = array[i];
usedSize++;
}
}
public void createHeap() {
for (int parent = (usedSize-1-1)/2; parent >= 0 ; parent--) {
shiftDown(parent,usedSize);
}
}
private void shiftDown(int parent, int usedSize) {
int child = (2*parent)+1;//左孩子下标
while (child < usedSize) {
if(child+1 < usedSize && elem[child] < elem[child+1]) {
child++;
}
//child一定是 左右孩子最大值的下标
if(elem[child] > elem[parent]) {
swap(child, parent);
parent = child;
child = 2*parent+1;
}else {
//已经是大根堆了
break;
}
}
}
private void swap(int i,int j) {
int tmp = elem[i];
elem[i] = elem[j];
elem[j] = tmp;
}
}
(向上调整)
注意:建堆的时间复杂度为O(N)
4.堆的插入与删除
1.堆的插入
public void offer(int val) {
if(isFull()) {
this.elem = Arrays.copyOf(elem,2*elem.length);
}
this.elem[usedSize] = val;//usedSize=10
//向上调整
shiftUp(usedSize);
usedSize++;
}
private void shiftUp(int child) {
int parent = (child-1)/2;
while (child > 0) {
if (elem[child] > elem[parent]) {
swap(child,parent);
child = parent;
parent = (child-1)/2;
} else {
break;
}
}
}
public boolean isFull() {
return usedSize == elem.length;
}
2.堆的删除
public int poll() {
int tmp = elem[0];
swap(0,usedSize-1);
usedSize--;
shiftDown(0,usedSize);
return tmp;
}
三.常用接口介绍
1.PriorityQueue的特性
关于使用PriorityQueue的使用要注意:
2.PriorityQueue常用接口介绍
1.优先级队列构造
import java.util.Comparator;
class IntCmp implements Comparator<Integer> {
public int compare(Integer o1, Integer o2){
return o2.compareTo(o1);
}
}
class Solution{
public static void main(String[] args) {
PriorityQueue<Integer>q = new PriorityQueue<>(new IntCmp());
q.offer(5);
q.offer(9);
q.offer(1);
q.offer(2);
q.offer(6);
System.out.println(q.poll());
System.out.println(q.poll());
System.out.println(q.poll());
}
}
1.没用比较器
2.用了比较器
2.插入/删除/获取优先级最高的元素
四.堆排序
public void heapSort() {
int end = usedSize-1;
while (end > 0) {
swap(0,end);
shiftDown(0,end);
end--;
}
}