/* file heapSort.h */ // code by bds, 2/00

#ifndef __HEAPSORT__
#define __HEAPSORT__
#include <iterator>

/* 
We require that class Iterator has the "pointer arithmetic" operations.
and that the unknown class - the keys - pointed to by dereferencing iterators 
has function swap and operator <= defined (and representing a linear order on 
keys).

A left-complete binary tree is a binary tree that is complete down to some depth
h and has any remaining elements at depth h+1 and in the leftmost positions at 
that depth.  Let p and e be iterators defining an array [p..e), and let k be an 
iterator such that p <= k < e.  The array [p..e) represents a left-complete 
binary tree by the convention that the node in position k has left subtree 
rooted at node k + (k-p) + 1 and right subtree rooted at node k + (k-p) + 2 
(provided these positions are less than e).  The roots of the left and right 
subtrees of k are also called the left and right children of k.

Note that every subtree of a left-complete tree is left-complete.  Also, for 
p < k < e, the array [k..e) contains a collection of subtrees of [p..e).

For example, consider a 10 element array starting in memory location 1000.  
p = 1000, e = 1010.
Children of k = 1000 are 1001 and 1002
Children of k = 1001 are 1003 and 1004
Children of k = 1002 are 1005 and 1006
Children of k = 1003 are 1007 and 1008
Left child of k = 1004 is 1009, no right child.
The rest are leaves.
*/
template<typename Iterator>
Iterator leftChild(Iterator k, Iterator p) { return k + (k-p) + 1; }

template<typename Iterator>
Iterator rightChild(Iterator k, Iterator p) { return k + (k-p) + 2; }

template<typename Iterator>
Iterator parent(Iterator k, Iterator p) { return p + (k-p-1)/2; }

/*
Let H be a left-complete tree with a key at each node, where the keys are 
elements of a linearly ordered set.  The tree H is said to have the heap 
property, if for every node the key of that node is no less than the keys of 
its left and right children.

Note that the key at the root of a heap is a largest key in the heap.
Baase and Van Gelder call the heap property the partial order property.
*/
/* 
upHeap(p, e) fixes a left-complete binary tree in range [p..e) that has the heap
property everywhere except that the last key (position e-1) may be greater than 
it's parent.  Remark: p is a necessary parameter to downHeap in order to know 
where the parent of k is.
*/
template <typename Iterator>
void upHeap(Iterator p, Iterator e)
{
	Iterator k = e-1;
	Iterator kk = parent(k, p);
	if ( k != kk && *k > *kk) { std::swap(*k, *kk); upHeap(p, kk); }
}

/*
downHeap(k, p, e) fixes a left-complete binary tree in range [p..e) that has the
heap property everywhere except that the k-th key may be less than one or both 
of it's children.  DownHeap is called fixHeap in Baase and Van Gelder.
Remark: p is a necessary parameter to downHeap in order to know where the 
children of k are.  e is necessary in order to know if the children even exist.
*/

template<typename Iterator>
void downHeap(Iterator k, Iterator p, Iterator e)
{ 
	Iterator left = leftChild(k, p);
	Iterator right = rightChild(k, p);
	if ( right < e && *left < *right && *k < *right) // right is biggest
	{ std::swap(*k, *right); downHeap(right, p, e); }
	else if ( left < e && *k < *left ) // left is biggest
	{ std::swap(*k, *left); downHeap(left, p, e); }
}
		
template<typename Iterator>
void heapSort(Iterator p, Iterator e) // sort the values in range [p..e).
{
  // The items *[p..e) will be permuted into sorted order.
  Iterator k;
  int n = e - p; // size of range to be sorted.

  // Phase I:  Build a heap.
  for (k = p + n/2; k >= p; --k) 
  {	// invariant: [k+1 .. e) has the heap property.
   	// Note that [p + n/2 + 1 .. e) automatically has the heap property.  
   	// It's just a bunch of leaves.
   	downHeap(k, p, e); 
  }
  // Now [p .. e) has the heap property.

  // Phase II:  Exploit the heap to get sorted.
  for (k = e-1; k > p; --k ) 
  {	// invariant: *[k+1 .. e) are the largest elements, sorted.
   	// and [p .. k] has the heap property.

   	std::swap(*p, *k); // wherein the largest in the heap moves from *p to *k

   	// Now *[k .. e) are the largest elements, sorted.
   	// but the heap may be broken at the root.
   	downHeap(p, p, k-1); 
  }
}

template<typename Iterator>
class PriorityQueue
{   public:
	typedef iterator_traits<Iterator>::valuetype Valuetype;
	Valuetype maxElement();
	void removeMax();
	void insert(Valuetype v);
	void increaseKey( Iterator k, Valuetype newkey ); 
	void delete( Iterator k );
	int size();
	bool isEmpty() { return size() == 0; };
    protected: 
	// implementation...
};

#endif  // __HEAPSORT__
