一、优先队列的意义
普通队列: FIFO
优先队列:与入队顺序无关 ; 和优先级相关()
操作系统中任务调度的优先级
动态选择优先级最高的任务执行
关键词:动态 处理任务调度
直接复用队列
所以 用堆可以很方便的实现二叉树
二、堆
2.1 二叉堆Binary Heap
二叉堆是一棵完全二叉树
满二叉树:除了叶子结点,其他的左右结点都不为空
完全二叉树:不一定是满二叉树,但是缺失部分一定在左下侧,从左到右(19 、17 、 15)
二叉堆的性质
- 堆中的某个节点的值总是不大约其父节点的值
- 最大堆(最小堆)
2.2 用数组实现二叉堆
如上图,可以用数组来实现二叉堆,
- 左节点 = i * 2
- 右节点 = i * 2 + 1
- 父节点 = i / 2
public class MaxHeap<E extends Comparable<E>> {
private Array<E> data;
public MaxHeap(int capacity){
data = new Array<>(capacity);
}
public MaxHeap(){
data = new Array<>();
}
// 返回堆中的元素个数
public int size(){
return data.getSize();
}
// 返回一个布尔值, 表示堆中是否为空
public boolean isEmpty(){
return data.isEmpty();
}
// 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
private int parent(int index){
if(index == 0)
throw new IllegalArgumentException("index-0 doesn't have parent.");
return (index - 1) / 2;
}
// 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
private int leftChild(int index){
return index * 2 + 1;
}
// 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
private int rightChild(int index){
return index * 2 + 2;
}
}
2.2.1 像堆中添加元素
直接添加到叶子节点,但是这样就会产生大小不满足小于父亲节点
Sift Up 上浮
// 向堆中添加元素
public void add(E e){
data.addLast(e);
siftUp(data.getSize() - 1);
}
private void siftUp(int k){
while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
data.swap(k, parent(k));
k = parent(k);
}
}
2.2.2 从堆中取出元素
堆的性质:只能取出 根节点的 元素(最大的元素)
维护堆的步骤:
- 最后一个元素 移动到 根节点
- 现在对比根节点 & 左右两个孩子结点,sift down 最大的
// 取出堆中最大元素
public E extractMax(){
E ret = findMax();
data.swap(0, data.getSize() - 1);
data.removeLast();
siftDown(0);
return ret;
}
private void siftDown(int k){
while(leftChild(k) < data.getSize()){
int j = leftChild(k); // 在此轮循环中,data[k]和data[j]交换位置
if( j + 1 < data.getSize() &&
data.get(j + 1).compareTo(data.get(j)) > 0 )
j ++;
// data[j] 是 leftChild 和 rightChild 中的最大值
if(data.get(k).compareTo(data.get(j)) >= 0 )
break;
data.swap(k, j);
k = j;
}
}
三、堆 实现 优先队列
public class PriorityQueue<E extends Comparable<E>> implements Queue<E> {
private MaxHeap<E> maxHeap;
public PriorityQueue(){
maxHeap = new MaxHeap<>();
}
@Override
public int getSize(){
return maxHeap.size();
}
@Override
public boolean isEmpty(){
return maxHeap.isEmpty();
}
@Override
public E getFront(){
return maxHeap.findMax();
}
@Override
public void enqueue(E e){
maxHeap.add(e);
}
@Override
public E dequeue(){
return maxHeap.extractMax();
}
}