更新说明
我们在此前已经编写过简单版的二叉大根堆V1.0,这次,换成二叉小根堆,命名为二叉堆V2.0。
大家也知道,堆是完全二叉树,存储方式借助动态数组实现顺序存储,依赖于父子结点之间的index关系实现类似于二叉树式的访问,也支持数组本身的按编号随机访问和顺序访问。
二叉堆和二叉搜索树有很大的不同,但新学的人可能会弄混,这里有二者的辨析文。
堆是很有用的一种数据结构,二叉堆是常见形式。
堆排序、优先队列、堆的其他变形……都离不开对二叉堆的理解。
很多算法题都能涉及到堆,堆还真是个好东西!
对于新手而言,也必须掌握二叉堆建堆、插入、删除、调整的代码,能编写堆排序的代码。
堆真的很重要,一定要掌握!!!
虽说有大根堆和小根堆,但无非一个是最大值在堆顶,一个是最小值在堆顶,其实是一个东西。不信的话,你品,你细品,又有什么差别呢?
好啦,开始正题,不懂的自己去学。
核心功能
- void insert(x) → Insert x
- Comparable deleteMin() → Return and remove smallest item
- Comparable findMin() → Return smallest item
- boolean isEmpty() → Return true if empty; else false
- void makeEmpty() → Remove all items
异常类
当集合容器为空的时候就不能够删除或获取元素,这时就会出现一种异常,命名为UnderflowException:
/**
* Exception class for access in empty containers
* such as stacks, queues, and priority queues.
*/
public class UnderflowException extends RuntimeException {}
编程实现
/**
* Implements a binary heap.
* Note that all "matching" is based on the compareTo method.
*/
public class BinaryHeap<T extends Comparable<? super T>> {
/**
* Construct the binary heap.
*/
public BinaryHeap() {
this(DEFAULT_CAPACITY);
}
/**
* Construct the binary heap.
* @param capacity the capacity of the binary heap.
*/
@SuppressWarnings("unchecked")
public BinaryHeap(int capacity) {
currentSize = 0;
array = (T[]) new Comparable[capacity+1];
}
/**
* Construct the binary heap given an array of items.
*/
@SuppressWarnings("unchecked")
public BinaryHeap(T[] items) {
currentSize = items.length;
array = (T[]) new Comparable[(currentSize+2)*11/10];
int i = 1;
for(T item : items) {
array[i++] = item;
}
buildHeap();
}
/**
* Insert into the priority queue, maintaining heap order.
* Duplicates are allowed.
* @param x the item to insert.
*/
public void insert(T x) {
if(currentSize == array.length-1) {
enlargeArray(array.length*2+1);
}
int hole = ++currentSize;
for(array[0] = x; x.compareTo(array[hole/2]) < 0; hole/=2) {
array[hole] = array[hole/2];
}
array[hole] = x;
}
@SuppressWarnings("unchecked")
private void enlargeArray(int newSize) {
T[] old = array;
array = (T[]) new Comparable[newSize];
for(int i = 0; i < old.length; i++) {
array[i] = old[i];
}
}
/**
* Find the smallest item in the priority queue.
* @return the smallest item, or throw an UnderflowException if empty.
*/
public T findMin() {
if(isEmpty()) {
throw new UnderflowException();
}
return array[1];
}
/**
* Remove the smallest item from the priority queue.
* @return the smallest item, or throw an UnderflowException if empty.
*/
public T deleteMin() {
if(isEmpty()) {
throw new UnderflowException();
}
T minItem = findMin();
array[1] = array[currentSize--];
percolateDown(1);
return minItem;
}
/**
* Establish heap order property from an arbitrary
* arrangement of items. Runs in linear time.
*/
private void buildHeap() {
for(int i = currentSize/2; i > 0; i--) {
percolateDown(i);
}
}
/**
* Test if the priority queue is logically empty.
* @return true if empty, false otherwise.
*/
public boolean isEmpty() {
return currentSize == 0;
}
/**
* Make the priority queue logically empty.
*/
public void makeEmpty() {
currentSize = 0;
}
private static final int DEFAULT_CAPACITY = 10;
private int currentSize; // Number of elements in heap
private T[] array; // The heap array
/**
* Internal method to percolate down in the heap.
* @param hole the index at which the percolate begins.
*/
private void percolateDown(int hole) {
int child;
T tmp = array[ hole ];
for(; hole*2 <= currentSize; hole = child) {
child = hole*2;
if(child != 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 class BinaryHeap {
public static void main(String [] args) {
int numItems = 10000;
BinaryHeap<Integer> h = new BinaryHeap<>();
int i;
for(i = 37; i != 0; i = (i+37) % numItems) {
h.insert(i);
}
for(i = 1; i < numItems; i++) {
if(h.deleteMin() != i) {
System.out.println("Oops! " + i);
}
}
}
}