
import java.util.Vector;

/* A simple Heap implementation.  This heap only supports insertion
   and removal from the top, since only those operations are necessary
   for this project.

   The elements of this Heap must implement the interface Heap.Element
*/

public final class Heap {
    public static interface Element {
	boolean HigherPriority(Element h);
    }

    // The branching factor of the heap: 2 is binary */
    private static final int N = 2;
    
    public Heap() {
	elements = new Vector();
    }

    // Insert a new element into the heap
    
    public void insert(Element h) {
	//System.out.println("insert: " + h.toString());
	//printHeap();
        elements.add(h);
	reHeapUp(elements.size()-1);
    }
    
    // Returns the top element without removing it

    public Element getTop() {
	if (isEmpty()) {
	    return null;
	}
	return (Element) elements.firstElement();
    }

    // Remove and return the top (highest priority) element of the heap --
    // returns null if the Heap is empty

    public Element removeTop() {
	//System.out.println("removeTop");
	//printHeap();
	if (isEmpty()) return null;


	Element ans = (Element) elements.firstElement();
	elements.setElementAt(elements.lastElement(),0);
	elements.remove(elements.size()-1);
	reHeapDown(0);
	return ans;
    }

    // Returns true if this Heap is empty

    public boolean isEmpty() {
	return (elements.size() == 0);
    }

    // Swap the elements at index's i and j -- both must be
    // within the bounds of the elements vector 

    private void swap(int i, int j) {
	Element temp = (Element) elements.elementAt(i);
	elements.setElementAt(elements.elementAt(j),i);
	elements.setElementAt(temp,j);
    }
    
    // Gets the parent index of element at index x 

    private int getParent(int x) {
	return (x - 1) / N;
    }
    
    // Gets the index of the first child of the element
    // at index x

    private int getFirstChild(int x) {
	return x * N + 1;
    }
    
    
    // Returns the child of the element at x
    // with the highest priority -- or -1 if
    // x has no children
    
    private int getHighestChild(int x) {
	int firstChild = getFirstChild(x);
	
	if (firstChild >= elements.size()) {
	    return -1;
        }

	int bestChild = firstChild;
	Element bestHE = (Element) elements.elementAt(firstChild);
	
	for (int i=1; i<N; i++) {
            if (firstChild+i >= elements.size()) {
		return bestChild;
            }
	    Element currHE = (Element) elements.elementAt(firstChild+i);
	    
	    if (currHE.HigherPriority(bestHE)) {
		bestChild = firstChild+i;
		bestHE = currHE;
	    }
        }
	return bestChild;
    }
    
    // Remakes the heap assuming that the only thing keeping
    // this heap from being a proper heap is that the element 
    // at index x may need to be moved up 
    
    private void reHeapUp(int x) {

	if (x == 0) { // We're at the top
	    return;
	}

	int pindex = getParent(x);

	Element currElement = (Element) elements.elementAt(x);
	Element pElement = (Element) elements.elementAt(pindex);

	if (currElement.HigherPriority(pElement)) {
	    // swap this element with it's parent and reHeapify
	    swap(pindex,x);
	    reHeapUp(pindex);
	}
    }

    // Remakes the heap assuming that the only thing keeping
    // this heap from being a proper heap is that the element 
    // at index x may need to be moved down

    private void reHeapDown(int x) {
	int hchild = getHighestChild(x);
	//System.out.println("reHeapDown: " + x + " " + hchild);
	
	if (hchild < 0) { // No children
	    return;
	}

	Element currElement = (Element) elements.elementAt(x);
	Element childElement = (Element) elements.elementAt(hchild);

	if (childElement.HigherPriority(currElement)) {
	    // swap this element with it's child and reHeapify
	    swap(x,hchild);
	    reHeapDown(hchild);
	}
    }

    // A dubugging method that prints out all the elements in the vector

    private void printHeap() {
	for (int i=0; i<elements.size(); i++) {
	    System.out.print(elements.elementAt(i).toString());
	    System.out.print(" ");
	}
	System.out.println("");
    }

    private Vector elements;
}


