// 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; } }