Java 实现大根堆
1. 大根堆
堆是一种比较常见的数据结构,在 Java 里有 PriorityQueue 就是堆的一种实现,自己代码实现堆结构有助于更好地理解这种数据结构,以便于我们能够更好地去运用它。
class MaxHeap {
int[] maxHeap;
int capacity; // 堆的容量
int size; // 堆实际大小
public MaxHeap(int n) {
maxHeap = new int[n];
capacity = n;
size = 0;
}
// 交换堆中 p q 下标对应的元素
private void swap(int p, int q) {
int tmp = maxHeap[p];
maxHeap[p] = maxHeap[q];
maxHeap[q] = tmp;
}
public void offer(int element) {
// 堆的大小已经到达了最大容量,不能再继续添加
if (isFull() == true) {
System.out.println("The MaxHeap is FULL!");
return;
}
maxHeap[size++] = element;
// 从添加处开始向上调整堆结构
int idxStart = size - 1;
int idxFather = (idxStart - 1) >> 1;
while (idxFather >= 0 && maxHeap[idxStart] > maxHeap[idxFather]) {
swap(idxStart, idxFather);
idxStart = idxFather;
idxFather = (idxStart - 1) >> 1;
}
}
public int peek() {
return maxHeap[0];
}
public int poll() {
// 堆为空,不能再弹出元素
if (isEmpty() == true) {
System.out.println("The MaxHeap is EMPTY!");
return -1;
}
int popVal = maxHeap[0];
maxHeap[0] = maxHeap[--size]; // 将堆中最后一个元素放置到堆顶
// 开始向下调整堆(因为上一步是将最后一个元素放置到堆顶,可能打破了大根堆的结构)
int idxStart = 0;
int idxLeft = (idxStart << 1) + 1, idxRight = idxLeft + 1;
int largest = 0;
while (idxLeft < size) {
// 找左右孩子中较大的那个,用 largest 记录其下标
if (idxRight < size && maxHeap[idxRight] > maxHeap[idxLeft]) {
largest = idxRight;
} else {
largest = idxLeft;
}
// 如果当前元素比左右孩子中较大的那个还大,说明依旧保持大根堆结构,不用再继续
if (maxHeap[idxStart] > maxHeap[largest]) {
break;
}
// 否则,将左右孩子中较大的那个替换到其父亲的位置,然后继续向下调整
swap(idxStart, largest);
idxStart = largest;
idxLeft = (idxStart << 1) + 1;
idxRight = idxLeft + 1;
}
return popVal;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public boolean isFull() {
return size == capacity;
}
}