/**
* 堆通常是一个可以被看做一棵树的数组对象。
* 堆总是满足下列性质:
* 堆中某个节点的值总是不大于或不小于其父节点的值;
* 堆总是一棵完全二叉树。
* 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
*/
public class MaxHeap {
public static class MyMaxHeap {
public int[] heap;
public final int limit;
public int heapSize;
public MyMaxHeap(int limit) {
this.heap = new int[limit];
this.limit = limit;
}
/**
* 往最大堆中添加一个元素
*
* @param value 元素
*/
public void push(int value) {
if (isFull()) {
System.out.println("the heap is full");
return;
}
heap[heapSize] = value;
heapInsert(heapSize++);
}
/**
* 往堆中添加一个元素,同时必须是最大堆
*
* @param index 新添加的元素的位置
*/
public void heapInsert(int index) {
int pIndex = 0;
// 此处 ((index - 1) / 2) 和 ((index - 1) >> 1) 计算结果是不一样的,当index=0,前者是0,后者是-1
while (heap[index] > heap[pIndex = ((index - 1) / 2)]) {
swap(heap, index, pIndex);
index = pIndex;
}
}
/**
* 弹出堆中的最大值,同时把该值从堆中移除掉
*
* @return 最大值
*/
public int pop() {
if (isEmpty()) {
System.out.println("the heap is empty");
return 0;
}
int max = heap[0];
swap(heap, 0, --heapSize);
heapify(heap, 0, heapSize);
return max;
}
/**
* 修改了一个元素之后,保持最大堆
*
* @param arr 堆
* @param index 修改的元素位置
* @param heapSize 堆大小
*/
public void heapify(int[] arr, int index, int heapSize) {
int left = (index << 1) + 1;
while (left < heapSize) {
int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
if (arr[index] >= arr[largest]) {
break;
}
swap(arr, index, largest);
index = largest;
left = (index << 1) + 1;
}
}
public boolean isFull() {
return heapSize == limit;
}
public boolean isEmpty() {
return heapSize == 0;
}
}
/**
* 交换数组两个元素的位置
*
* @param arr 数组
* @param i 位置
* @param j 位置
*/
private static void swap(int[] arr, int i, int j) {
// 同一个位置交换无意义,并且用异或交换会有问题
if (i == j) {
return;
}
// 交换
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
}
/* 如有错误,欢迎批评指正 */