/*
 * BinaryHeap.h
 *
 *  Created on: 2013Sept by bds
 *  Evolved from BinaryHeap.h of Morin
 *  Uses ArrayStack 
 *  Documented in ODS Chapter 10
 */

#ifndef BINARYHEAP_H_
#define BINARYHEAP_H_

#include "ArrayStack.h"

namespace ods {

template<class T> // bool compare(T x, T y) must be exist.
class BinaryHeap : public ArrayStack<T> {
protected:
	// helper function
	static int left(int i) { return 2*i + 1; }
	static int right(int i) { return 2*i + 2; }
	static int parent(int i) { return (i-1)/2; }
	void bubbleUp(int i);
	void trickleDown(int i);
	using ArrayStack<T>:: a;
	using ArrayStack<T>:: n;
	using ArrayStack<T>:: add; // add(i,x)
	using ArrayStack<T>:: remove; // remove(i)
public:
	// priority queue functions
	void add(T x);
	T remove();
	T findMin() { return a[0]; }
};

template<class T>
void BinaryHeap<T>::add(T x) {
	add(n, x);
	bubbleUp(n);
}

template<class T>
void BinaryHeap<T>::bubbleUp(int i) {
// Requires:  Heap property true everywhere except possibly at parent(i).
// Promises:  Heap property true everywhere.
	if (i == 0) return; // at root: no parent, so done.
	int p = parent(i);
	if ( compare(a[i], a[p]) < 0 ) {
		std::swap(a[i], a[p]);
		bubbleUp(p);
	}
}

template<class T>
T BinaryHeap<T>::remove() {
	T ans = a[0];
	a[0] = a[n-1];
	remove(n-1);
	trickleDown(0);
	return ans;
}

template<class T>
void BinaryHeap<T>::trickleDown(int i) {
// Requires:  Heap property true everywhere except possibly at i.
// Promises:  Heap property true everywhere.
	int l = left(i);
	int r = right(i);

	if (l >= n) return; // no children, so done.

	int m = l; 
	if ( r < n and compare (a[r], a[m]) < 0 ) m = r;
	// now m is the index of the minimal child
	if ( compare(a[m], a[i]) < 0 ) {
		std::swap(a[i],a[m]);
		trickleDown(m);
	}
}

} /* namespace ods */
#endif /* BINARYHEAP_H_ */
