来自维基的解释:堆通常是一个可以被看做一棵树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。[1]
性质:
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。
- 任意节点小于它的所有后裔,最小元在堆的根上(堆序性)。
- 堆总是一棵完全树。
各种操作时间复杂度
操作 | 描述 | 时间复杂度 |
---|---|---|
build | 建立一个空堆 | O(n) |
insert | 向堆中插入一个新元素 | |
update | 将新元素提升使其符合堆的性质 | |
get | 获取当前堆顶元素的值 | O(1) |
delete | 删除堆顶元素 | |
heapify | 使删除堆顶元素的堆再次成为堆 |
package org.jerry.datastructure;
public class BinaryHeap<T extends Comparable<? super T>> {
/** store data and abort array[0] */
private T[] array;
/** the current number of data in heap */
private int currentSize;
/** default capacity */
private static final int DEFAULT_CAPACITY = 10;
public BinaryHeap() {
this(DEFAULT_CAPACITY);
}
public BinaryHeap(int size) {
currentSize = 0;
array = (T[]) new Comparable[size + 1];
}
/**
* Insert an element
* @param x
*/
public void insert(T x) {
if (currentSize == array.length - 1)
enlargeArray(array.length * 2 + 1);
// int hole = ++currentSize; // 大小加1
siftup(++currentSize, x);
}
/**
* 为将元素X插入堆中,找到空闲位置,建立一个空穴,若满足堆序性(英文:heap order),则插入完成;
* 否则将父节点元素装入空穴,删除该父节点元素,完成空穴上移。直至满足堆序性。这种策略叫做上滤(percolate up)。[1]
* @param hole
* @param x
*/
private void siftup(int hole, T x) {
for (; hole > 1 && x.compareTo(array[hole / 2]) < 0; hole /= 2)
array[hole] = array[hole / 2];
array[hole] = x;
}
/**
* 堆大小扩大一倍
* @param size
*/
private void enlargeArray(int size) {
T[] old = array;
array = (T[]) new Comparable[size];
for (int i = 1; i < old.length; ++i)
array[i] = old[i];
}
public T findMin() {
if (currentSize < 1)
return null;
return array[1];
}
public boolean isEmpty() {
return currentSize == 0;
}
public void makeEmpty() {
currentSize = 0;
}
public T deleteMin() {
if (isEmpty())
return null;
T minItem = findMin();
array[1] = array[currentSize--];
siftdown(1);
return minItem;
}
/**
* DeleteMin,删除最小元,即二叉树的根或父节点。
* 删除该节点元素后,队列最后一个元素必须移动到堆得某个位置,使得堆仍然满足堆序性质。这种向下替换元素的过程叫作下滤。
* @param hole
*/
private void siftdown(int hole) {
T tmp = array[hole];
int child = 0;
for (; hole * 2 <= currentSize; hole = child) {
child = hole * 2;
if (child + 1 <= currentSize && array[child + 1].compareTo(array[child]) < 0)
child++;
if (array[child].compareTo(tmp) < 0)
array[hole] = array[child];
else
break;
}
array[hole] = tmp;
}
public int size() {
return currentSize;
}
public void buildHeap() {
for (int i = currentSize / 2; i > 0; --i)
siftdown(i);
}
}