+--+
| | <--- root
+--+
/ \
/ \
/ \
+ +
/ \ / \
left subtree ---> / \ / \ <--- right subtree
/ \ / \
+-------+ +-------+
Definition: The height of an empty (rooted binary) tree is -1. The height of a non-empty (rooted binary) tree is one more than the larger of the heights of its left and right subtrees.
Definition: A (rooted) binary tree T of height h>0 is said to be complete if, for all k satisfying 0≤k<h, the number of nodes at distance k from the root of T is 2k (which is to say that the number of nodes on "level k" is the maximum possible) AND any "missing node" on level h must be to the right of all (existing) nodes on that level. Hence, the outline of a complete binary tree looks like a Christmas tree, possibly with a chunk missing from the bottom right corner (where nodes are missing):
+
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ +-------+
+------------+
Definition: A heap is a complete binary tree satisfying the property that, for any nodes u and v, if u is the parent of v, then the "key value" in u is less than or equal to the key value in v.
Definition: A priority queue is a collection of items, each of which has associated with it a "priority". For simplicity, we assume that priorities are expressed via integers and that the smaller the integer, the higher the priority it represents. Three operations are defined on priority queues:
A heap is an effective way of representing a priority queue.
public class PriorityQueue {
/* pre: initSize > 0 && comp defines a total ordering on the
* universe of objects from which will be drawn the elements
* that are inserted into the PQ.
* post: initializes 'this' with room enough for initSize elements
*/
public PriorityQueue(Comparator comp, int initSize) {
b = new Object[initSize];
nodeCntr = 0;
c = comp;
}
/* pre: comp defines a total ordering
post: constructs an empty PQ
*/
public PriorityQueue(Comparator comp)
{ this(comp, defaultInitSize); }
public void insert(Object x) {
if (nodeCntr == b.length) { // if b is full, double its length
Object[] temp = b;
b = new Object[2*nodeCntr];
for (int i=0; i != b.length; i = i+1)
{ b[i] = temp[i]; }
}
b[nodeCntr] = x;
siftUp(nodeCntr);
nodeCntr = nodeCntr + 1;
}
public int getMin() { return b[0]; }
public void deleteMin() {
b[0] = b[nodeCntr - 1];
nodeCntr = nodeCntr - 1;
siftDown(0);
}
/* <<<< P R I V A T E >>>> */
/* <<<< i n s t a n c e v a r i a b l e s >>>> */
private Comparator c; // for comparing items in heap
private Object[] b; // array to hold values in heap
private int nodeCntr // b[0..nodeCntr-1] contain values in heap
private static final int defaultInitSize = 8;
private boolean lessThan(Object a, Object b)
{ return c.compare(a, b) < 0; }
/* <<<< navigation operations >>>> */
private int rootLoc() { return 0; }
private int parentLoc(int v) { return (v-1) / 2; }
private int leftChildLoc(int v) { return 2*v + 1; }
private int rightChildLoc(int v) { return 2*v + 2; }
/* <<<< observer operations >>>> */
private boolean hasLeftChild(int v)
{ return leftChildLoc(v) < nodeCntr; }
private boolean hasRightChild(int v)
{ return rightChildLoc(v) < nodeCntr; }
private boolean isLeaf(int v) { return !hasLeftChild(v); }
private siftUp(int k) {
if (k = rootLoc()) { }
else if (lessThan(b[k], b[parentLoc(k)])) {
swap(b, k, parentLoc(k) );
siftup( parentLoc(k) );
}
}
private siftUpIterative(int k) {
while ( k != rootLoc() && lessThan(b[k], b[parentLoc(k)]) ) {
swap(b, k, parentLoc(k) );
k = parentLoc(k);
}
}
private siftDown(int k) {
if ( isLeaf(k) ) { }
else {
int leftLoc = leftChildLoc(k);
int rightLoc = rightChildLoc(k);
int lesserChildLoc;
if ( hasRightChild(k) ) {
if ( lessThan( b[leftLoc], b[rightLoc] ) )
{ lesserChildLoc = leftLoc; }
else
{ lesserChildLoc = rightLoc; }
else
{ lesserChildLoc = leftLoc; }
}
if ( lessThan( b[lesserChildLoc], b[k] ) ) {
swap(b, k, lesserChildLoc );
siftDown( lesserChildLoc );
}
}
}