文章目录
本文的优先队列基于大顶堆实现:数据结构(8)-二叉堆
优先队列是一种用来维护一组元素构成的结合S的数据结构,其中每个元素都有一个关键字key,元素之间的比较都是通过key来比较的。优先队列包括最大优先队列和最小优先队列,优先队列的应用比较广泛,比如作业系统中的调度程序,当一个作业完成后,需要在所有等待调度的作业中选择一个优先级最高的作业来执行,并且也可以添加一个新的作业到作业的优先队列中。Java中,PriorityQueue的底层数据结构就是堆(默认为小顶堆)。
一、基本操作
对于优先队列,只实现两个外部可调用的基本操作:一是插入元素,二是删除最大元素。
- 插入元素
我们将新元素添加到数组末尾,增加堆的大小并让这个新元素上浮到合适的位置
- 删除最大元素
我们从数组顶端删去最大的元素并将数组的最后一个元素放到顶端,减少堆的大小并且让这个元素下沉到合适的位置
二、Java代码实现
//大顶堆实现的优先队列
public class MaxPQ {
//二叉堆节点数
int size;
//构造二叉堆的数组
int[] a;
//二叉堆最大大小
int max;
public BinaryHeap(int length) {
//初始节点数为0
size = 0;
//初始化有长度的二叉堆数组[长度加一是因为节点以1开始]
max = length + 1;
a = new int[max];
}
/**
* 判断是否为空堆
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 堆大小
*/
public int size() {
return size;
}
/**
* k节点上游调整堆平衡
*/
public void swim(int k) {
while (k > 1 && a[k] > a[k/2]) {
//当k节点不为根节点且大于其父节点时上浮到父节点位置
int temp = a[k];
a[k] = a[k / 2];
a[k / 2] = temp;
//重新定位节点位置
k = k / 2;
}
}
/**
* k节点下浮调整堆平衡
*/
public void sink(int k) {
while (2 * k <= size) {
//目前j为左子节点
int j = 2 * k;
//比较左子节点和右子节点哪个大,将节点位置调整为大的子节点
if (j < size && a[j] < a[j + 1]) {
j++;
}
//j代表的子节点和父节点k比较,调整位置
if (a[k] >= a[j]) {
break;
}
//k < j
int temp = a[k];
a[j] = a[k];
a[k] = temp;
//重新定位k的位置
k = j;
}
}
/**
* 判断堆是否饱和
*/
public boolean isFull() {
return size >= max;
}
/**
* 在堆低插入数据并且调整堆平衡
*/
public void insert(int value) {
if (isFull()) {
return;
}
a[++size] = value;
//调整该节点位置使其平衡
swim(size);
}
/**
* 删除根节点并调整平衡
*/
public int delMax() {
if (!isEmpty()) {
int rootValue = a[1];
//交换根节点和最后一个节点(最小节点)的位置并将堆大小减小
a[1] = a[size];
a[size] = rootValue;
//将堆最后一个节点置为0标识被删除,且把堆节点数减少1
a[size--] = 0;
//将根节点下浮并调整堆平衡
sink(1);
return rootValue;
}
return 0;
}
}