
/**
 * Basic class for implementing the heapsort algorithm. 
 * This class works only for integers.
 *
 * @author Dr. Caffeine
 */
public class Heap
{
    
//----------------------------------
//    Data Members
//----------------------------------

    /**
     * Integer array for implementing a heap
     */
    private int[ ] heap;
    
    /**
     * Integer array for the sorted list
     */
    private int[ ] sortedList;
  
//----------------------------------
//    Constructors
//----------------------------------
    
    /**
     * Default constructor
     */
    public Heap( )
    {
        
        
    }

    
//-------------------------------------------------
//      Public Methods:
// 
//          void   setData   (   int[]      )
//          int[]  sort      (              )
//
//------------------------------------------------

    /**
     * Sets the interal array to the passed data.
     *
     * @param data an int array to be sorted
     */
    public void setData( int[ ] data )
    {
        heap       = new int[ data.length ];
        sortedList = new int[ data.length ];
        
        for (int i = 0; i < data.length; i++ ) {
            heap[i] = data[i];
     //       System.out.println( heap[i] ); //TEMP
        }
              
    }
    
    /**
     * Sorts the array using heapsort and returns the sorted list.
     *
     * @return a sorted array of int
     */
    public int[] sort( )
    {
        construct( ); //construction phase: construct the heap
        
        extract( );  //extraction phase: extract root nodes
        
        return sortedList;
        
    }
    
    
//-------------------------------------------------
//      Private Methods:
// 
//          void   construct (          )
//          void   extract   (          )
//          int    maxChild  ( int, int )
//          void   swap      ( int, int )
//          void   testPrint ( int      )
//
//------------------------------------------------
    
    /**
     * Performs the construction phase of the heapsort.
     */
    private void construct( )
    {
        int     current, maxChildIndex;
        boolean done;
        
        for (int i = (heap.length-2) / 2; i >= 0; i--) {
            
            current = i;
            done    = false;
            
            while ( !done ) {
                
                if ( 2*current+1 > heap.length-1 ) {
                    //current node has no children, so stop
                    done = true;
                }
                else {
                    //current node has at least one child, get the index of larger child
                    maxChildIndex = maxChild( current, heap.length-1 );
                    
                    if ( heap[current] < heap[maxChildIndex] ) {
                        
                        swap( current, maxChildIndex );
                        current = maxChildIndex;
                    }
                    else { //value relationship constraint is satisfied, so stop
                        done = true;
                    }
                }
            }
        }
            
    }
    
    /**
     * Performs the extraction phase of the heapsort
     */
    private void extract( )
    {
        int     current, maxChildIndex;
        boolean done;
        
        for (int size = heap.length-1; size >= 0; size--) {
            
            //remove the root node data
            sortedList[size] = heap[ 0 ];
            
            //move the last node to the root
            heap[ 0 ] = heap[size];
            
            //rebuild            
            current = 0;
            done    = false;
            
            while ( !done ) {
                
                if ( 2*current+1 > size ) {
                    //current node has no children, so stop
                    done = true;
                }
                else {
                    //current node has at least one child, get the index of larger child
                    maxChildIndex = maxChild( current, size );
                    
                    if ( heap[current] < heap[maxChildIndex] ) {
                        
                        swap( current, maxChildIndex );
                        current = maxChildIndex;
                    }
                    else { //value relationship constraint is satisfied, so stop
                        done = true;
                    }
                }
            }
            
            //testPrint( size ); //TEMP
          
        }
    }
    
    /**
     * Finds the position of the larger child of a node 
     * at position 'location'.
     *
     * @param location the position of a node
     * @param end      the position of the last node in this heap
     *
     * @return the position of a larger child
     */
    private int maxChild( int location, int end )
    {
        //Precondition: node at location has at least one child
        
        int result, leftChildIndex, rightChildIndex;
        
        rightChildIndex = 2*location + 2;
        leftChildIndex  = 2*location + 1;
        
        if ( rightChildIndex <= end &&
             heap[leftChildIndex] < heap[rightChildIndex]) {
                 
            result = rightChildIndex;
        }
        else {
            result = leftChildIndex;
        }
        
        return result;
    }
    
    
    /**
     * Swaps the values in positions loc1 and loc2
     *
     * @param loc1 the position of the first int
     * @param loc2 the position of the second int
     */
    private void swap ( int loc1, int loc2 )
    {
        int temp;
        
        temp = heap[loc1];
        heap[loc1] = heap[loc2];
        heap[loc2] = temp;
    }
    
    
    /**
     * Print out the elements for verificatio purpose
     */
    private void testPrint( int limit )
    {
                
        for (int i = 0; i < limit; i++) {   
            
            System.out.print("   " + heap[i]);
            
        }
        
        System.out.println( "   " );
    }
        
}
                    
    
    