// file:    heapsort.java
// author:  Robert Keller
// purpose: illustrating a fast, in-place, sorting program

import java.lang.*;
import java.io.*;
import java.util.*;

class heapsort
  {
  private float array[];        // The array being sorted

  /**
    *  Calling heapsort constructor on array of floats sorts the array.
    *  Parameter N is the number of elements to be sorted.
   **/

  heapsort(float array[], int N)
    {
    this.array = array;
    int Last = N-1;

    // A heap is a tree in which each node is smaller than either of its
    // children (and thus than any of its descendants).  All sub-trees of a
    // heap are also heaps.  In this program, a heap is stored as an array,
    // with the root at element 0.  In general, if a node is at element I,
    // its children are at elements 2*I+1 and 2*I+2.


    // phase 1: form heap
    // Construct heap bottom-up, starting with small trees just above leaves
    // and coalescing into larger trees near the root.

    for( int Top = Last/2; Top >= 0; Top-- )
      {
      adjust(Top, Last);
      }


    // phase 2: use heap to sort
    // Move top element (largest) out of heap, swapping with last element 
    // and changing the heap boundary, until only one element remains.

    while( Last > 0 )
      {
      swap(0, Last);
      adjust(0, --Last);
      }
    }


  /**
    *  adjust(Top, Last) adjusts the tree between Top and Last
   **/

  void adjust(int Top, int Last)
    {
    float TopVal = array[Top];                  // Set aside top of heap
    int Parent, Child;

    for( Parent = Top; ; Parent = Child )       // Iterate down through tree
      {
      Child = 2*Parent+1;                       // Child means left child

      if( Child > Last ) 
        break;                                  // Left child non-existent

      if( Child+1 <= Last                       // Right child exists
           && array[Child] < array[Child+1] )   // and right child is larger
        Child++;                                // Child is the larger child

      if( TopVal >= array[Child] ) 
        break;                                  // Location for TopVal found

      array[Parent] = array[Child];             // Move larger child up in tree
      }

    array[Parent] = TopVal;                     // Install TopVal in place
    }


  /**
    *  swap(i, j) interchanges the values in array[i] and array[j]
   **/

  void swap(int i, int j)
    {
    float temp = array[i];
    array[i] = array[j];
    array[j] = temp;
    }


  /**
    *  test program for heapsort; reads arbitrarily-many numbers 
    *  from standard input, sorts them, then writes them to standard output.
   **/

  public static void main(String[] args)
    {
    StreamTokenizer in = new StreamTokenizer(System.in);

    int Size = 1;                       // initial allocation
    int N = 0;                          // number of elements in array
    float array[] = new float[Size];    // initial array allocation

    try
      {
      // while more numbers in file
      while( in.nextToken() != java.io.StreamTokenizer.TT_EOF ) 
        {
        if( N == Size )                 // if the array is full
          {
          array = reallocate(array);    // float the array size
          Size *= 2;    
          }
        array[N++] = (float)in.nval;    // put item in array
        }
      }
      catch(IOException e)
      {
      System.err.println("*** IOException caught");
      }

    Date startTime = new Date();

    System.err.println("Sorting started");

    new heapsort(array, N);		// calling constructor sorts

    Date endTime = new Date();

    long time = endTime.getTime() - startTime.getTime();

    System.err.println("Sorting finished in " + time + " ms");

    for( int i = 0; i < N; i++ )
      {
      System.out.print(array[i] + " ");
      }    

    System.out.println();

    System.err.println("Sorting " + N + " elements using heapsort took " + 
                        time + " ms");
    }


  /**
    *  reallocate allocates a new array float the size of the original
    *  and copies the original into it.  The new array is returned.
   **/

  static float[] reallocate(float array[])
    {
    float[] newArray = new float[2*array.length];
    for( int i = 0; i < array.length; i++ )             // copy old array
      newArray[i] = array[i];    
    return newArray;
    }
  }
