/* file BinaryHeap.h */ // code by bds, 4/10

#ifndef __BINARY_HEAP_H
#define __BINARY_HEAP_H
#include <vector>
using namespace std;

template< typename Key > 
class Heap {
/* These public Priority Queue member functions are defined at the bottom:
 * (constructor) Heap ( vector<Key>& )
 * Node extractMin(); // return node v with least key(v).
 * void insert( Node v ); // application will have set key(v).
 * void decreaseKey( Node v);  // app will have decreased key(v).
 * bool isEmpty(); // true when heap is empty.
 */
	// reverse this comparison to make a max-heap.
	bool isLess(const Key& a, const Key& b){ return a < b; }

	typedef int Node; // an index valid in the keys and locations vectors.  
	typedef int Location; // an index valid for theHeap itself

	int n; // the current size of the heap;
	vector<Node> theHeap; // indexed by Location
	vector<Key>& priorities; // indexed by Node
	vector<Location> locations; // indexed by Node. gives location in theHeap.
	// These functions simply allow use of parentheses instead of square brackets.
	Key& key(Node v) { return priorities[v]; } 
	Location& location (Node v) { return locations[v]; }
	Node& heap(Location v) { return theHeap[v]; }

	// invariants:  For all nodes v, heap(location(v)) == v. 
	//              for all locations k, location(heap(k)) == k.


	/* Heap invariants:
	 * 1. the node with minimal key is at heap(0).
	 * 2. The heap property is maintained: 
	 *    for all locations k in 0..n-1, 
	 *    not isLess ( key(heap(k)), key(heap(parent(k))) ). 
	 */

	// These functions give adjacent nodes in the heap 
	// from the complete tree perspective.
	Node parent(Node v) { return heap( (location(v) - 1)/2 ); }
	Node leftChild(Node v) { return heap( 2*location(v) + 1 ); }
	Node rightChild(Node v) { return heap( 2*location(v) + 2 ); }
	
	void bubbleup( Node v ) { // aka "upheap"
	/* Input: A node v in the heap, the only node at which the heap 
	 *   property may be violated.
	 * Result: Some node locations may change. Heap property is restored.
	 * Cost: O(log(n)), where n is the heap's current size.
	 */
		while (location(v) != 0 and isLess( key(v), key(parent(v))) ) {
			Node p = parent(v);
			swap( heap(location(v)), heap(location(p)) ); 
			swap( location(v), location(p) ); 
		}
	}

	void siftdown( Node v ) { // aka "downheap"
	/* Input: A node v in the heap. the children of v are the only nodes 
	 *   at which the heap property may be violated.
	 * Result: Some node locations may change. Heap property is restored.
	 * Cost: O(log(n)), where n is the heap's current size.
	 */
		while ( location(leftChild(v)) < n ) {
			Node c = leftChild(v);
			if ( location(rightChild(v)) < n
				and 
			     isLess( key(rightChild(v)), key(c)) ) 
				c = rightChild(v);
			// now c is the child with minimal key.
			if ( isLess(key(c), key(v)) ) {
				swap(heap(location(v)), heap(location(c))); 
				swap(location(v), location(c)); 
			} else break;
		}
	}

	public:

	// Heap constructor
	Heap ( vector<Key>& vec ) 
	: n(0), theHeap(vec.size()), priorities(vec), locations(vec.size())  {}

	Node extractMin() {
	/* Condition: heap must be non-empty.
	 * Result: heap size is decreased by 1.  Locations of some 
	 *   nodes within the heap are changed.
	 * Output: the removed node having minimal key. 
	 * Cost: O(log(n)), where n is the heap's current size.
	 */
		Node minNode = heap(0);
		// swap first (min) and last nodes in heap.
		swap( heap(0), heap(n-1) ); 
		swap( location(heap(0)), location(heap(n-1)) ); 
		--n; // effectively removes back node from heap.

		siftdown( heap(0) ); // restore heap property
		return minNode;
	}

	void insert( Node v ) {
	// Input: A node to be inserted in the heap. 
	// 	Application has already set key(v).
	// Result: node v is inserted.  Heap size grows by one.
	//  Locations of v and some other nodes may be changed to maintain heap property.
	// Cost: O(log(n)), where n is the heap's current size.
		location( v ) = n;
		heap( n++ ) = v;
		bubbleup( v );
	}

	void decreaseKey( Node v ) {
	// Input: Node v in the heap. Application has decreased key(v).
	// Result: Locations of v and some other nodes may be changed 
	// 	to re-establish the heap property.
	// Cost: O(log(n)), where n is the heap's current size.
		bubbleup( v ); 
	}

	bool isEmpty() { 
	// Output: true if and only if there are no nodes in the heap currently.
	// Cost: O(1).
		return n == 0; 
	}
};

#endif  // __BINARY_HEAP_H
