+--+ | | <--- 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 min-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. (In a max-heap, replace "less" in the sentence above with "greater".)
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 ); } } }