概念
数据结构应该提供两个最基本的操作,一个是返回最高级优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)
- 堆逻辑上是一个完全二叉树
- 堆物理上是保存在数组中
- 满足任意节点的值都大于他子树中结点的值,叫做大堆,或大根堆
- 反之,叫做小堆,或小根堆
- 堆的基本作用是快速找集合中的最值
三级目录
内部原理
优先级队列的实现方式有很多,但最常见的是使用堆来构建
操作步骤
向下调整
- 左右子树必须是一个堆,才能调整
- 如果已经是叶子结点,则整个调整过程结束
1.判断当前位置有没有孩子
2.堆是完全二叉树,没有左孩子就一定没有右孩子,要判断是否有左孩子
3.堆的存储结构是数组,判断是否有左孩子及下标是否越界 - 确定左孩子或者右孩子,谁是最小孩子
1.右孩子不存在
2.比较array[left] 和 array[right] 值的大小,选择小的为min - 比较当前值和最小值
- 否则,交换当前和最小值
- 然后因为min 位置的堆的性质可能被破坏,向下重复以上过程
操作入队列
- 首先按尾插方式放入数组
- 比较它和双亲的值的大小,如果双亲值大,则满足堆的性质,插入结束
- 否则,交换它和双亲的位置的值,重新进行2.3步骤
- 直到根结点
代码实现如下:
public class MyPriorityQueue {
public int[] elem;
public int usedSize;
public MyPriorityQueue() {
this.elem = new int[10];
}
// 创建大根堆
public void adjustDown(int parent, int len) {
int child = 2 * parent + 1;
while (child < len) {
// 获取子节点最大值的下标
if (child + 1 < len && this.elem[child] < this.elem[child + 1]) {
child++;
}
if (this.elem[child] > this.elem[parent]) {
int tmp = this.elem[child];
this.elem[child] = this.elem[parent];
this.elem[parent] = tmp;
parent = child;
child = 2 * parent + 1;
} else {
break;
}
}
}
public void createHeap(int[] array) {
for (int i = 0; i < array.length; i++) {
this.elem[i] = array[i];
this.usedSize++;
}
for (int p = (this.usedSize - 1 - 1) / 2; p >= 0; p--) {
adjustDown(p, this.usedSize);
}
}
// 入堆
public void push(int key) {
if (isFull()) {
// 扩充容量
this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);
}
this.elem[this.usedSize] = key;
this.usedSize++;
adjustUp(this.usedSize - 1);
}
public boolean isFull() {
return this.usedSize == this.elem.length;
}
public boolean isEmpty() {
return this.usedSize == 0;
}
// 出堆(删除)
public void pop() throws UnsupportedOperationException {
if (isEmpty()) {
throw new UnsupportedOperationException("队列为空!");
}
if (isFull()) {
return;
}
int tmp = this.elem[0];
this.elem[0] = this.elem[this.usedSize - 1];
this.elem[this.usedSize - 1] = tmp;
this.usedSize--;
adjustDown(0, this.usedSize);
}
// 出堆(不删除)
public int getTop() throws UnsupportedOperationException {
if (isEmpty()) {
throw new UnsupportedOperationException("队列为空!");
}
return this.elem[0];
}
}