Binary Heap:
一个二叉堆(Binary Heap)是具有下面一些属性的二叉树:
1)是一个完全二叉树,即:除了叶子节点以外的其他节点全部有左右子树,并且最后一层的叶子节点按照从左到右填充。
2) 一个二叉堆可以是最大堆或者最小堆。 在最大堆中,根节点的值最大; 在最小堆中,根节点的值最小;
3) 所有子树符合性质2)
最小二叉堆实例
10 10
/ \ / \
20 100 15 30
/ / \ / \
30 40 50 100 40
二叉堆如何表示
二叉堆是一个完全二叉树,可以用数组来表示。
根节点在数组arr[0]的位置
下面的列表中展示对于第i个node 的父,左,右节点的位置
- Arr[i-1/2] Returns the parent node
- Arr[(2*i)+1] Returns the left child node
- Arr[(2*i)+2] Returns the right child node
使用二叉树的层次遍历得到数组。
二叉堆的应用
(1) 堆排序 Heap Sort: 在O(nLogn)时间内排序;
(2) Priority Queue: Binary Heap支持O(logn)时间的insert() delete() 和extractmax().
(3)图算法,如Dijkstra’s Shortest Path and Prim’s Minimum Spanning Tree.
(4) 许多问题可以使用堆解决,如:
a) K’th Largest/minimum Element in an array.
b) Sort an almost sorted array
c) Merge K Sorted Arrays.
最小堆上的操作
(1)获取最小值(getMin):返回根节点,时间复杂度为O(1);
(2)删除最小值extractMin():删除根节点,重建堆, O(logn)
(3)insert(), 在树的末端添加节点,如果节点比parent大,则return, 否则需要向上遍历重建, O(logn)。
Binary Heap相关代码
public class BinaryHeap {
private static final int DIVID = 2;
private int heap_size;
private int[] heap;
public BinaryHeap(int capacity) {
heap_size = 0;
heap = new int[capacity];
Arrays.fill(heap, -1);
}
public boolean isEmpty() {
return this.heap_size == 0;
}
public boolean isFull() {
return this.heap_size == heap.length;
}
//返回parent的index
private int parent(int index) {
return (index - 1) / DIVID;
}
public int leftChild(int index) {
return index * DIVID + 1;
}
public int rightChild(int index) {
return index * DIVID + 2;
}
// 插入元素i
public void insert(int i) {
if (isFull())
throw new NoSuchElementException("Overflow Exception");
/** Percolate up **/
heap[heap_size++] = i;
heapifyUp(heap_size - 1);
}
public int findMin() {
if (isEmpty())
throw new NoSuchElementException("Underflow Exception");
return heap[0];
}
public int deleteMin() {
int keyItem = heap[0];
delete(0);
return keyItem;
}
public int delete(int index) {
if (isEmpty())
throw new NoSuchElementException("Underflow Exception");
int keyItem = heap[index];
heap[index] = heap[heap_size - 1];
heap_size--;
heapifyDown(index);
return keyItem;
}
private void heapifyUp(int childIndex) {
int tmp = heap[childIndex];
while (childIndex > 0 && tmp < heap[parent(childIndex)]) {
heap[childIndex] = heap[parent(childIndex)];
childIndex = parent(childIndex);
}
heap[childIndex] = tmp;
}
private void heapifyDown(int index) {
int childIndex;
int tmp = heap[index];
while (hasChild(index)) {
childIndex = minChildIndex(index);
if (heap[childIndex] < tmp)
heap[index] = heap[childIndex];
else
break;
index = childIndex;
}
heap[index] = tmp;
}
private int minChildIndex(int index) {
if (DIVID * index + 2 < heap_size || heap[DIVID * index + 1] < heap[DIVID * index + 2]) {
return DIVID * index + 1;
}
return DIVID * index + 2;
}
private boolean hasChild(int index) {
return DIVID * index + 1 < heap_size;
}
}
public class BinaryHeapTest {
@Test
public void test(){
BinaryHeap binaryHeap = new BinaryHeap(5);
binaryHeap.insert(1);
binaryHeap.insert(4);
binaryHeap.insert(2);
binaryHeap.insert(5);
binaryHeap.insert(0);
binaryHeap.deleteMin();
}
}