// This is a utility class for FindRank class intPair { public int i, v; public intPair( int i, int v ){ this.i = i; this.v = v; } } /** John P. Cataldo <cataldoj@ccs.neu.edu>
Daniel Rinehart <danielr@ccs.neu.edu>
Aris Yannopoulos <aris@ccs.neu.edu>
COM1390 Programming Assignment #1

$Id: FindRank.java,v 1.6 1999/02/16 21:37:38 danielr Exp $

Determine if a biased pick will work and if so find the correct index to partition around. */ public class FindRank extends Object { //-- METHODS -- /** Based on where the single rank we are looking for in the range p to r it might make sense to bias the partition towards one end. @param S the array of numbers to use for value comparisons @param p the begin point of the range to consider @param r the end point of the range to consider @param K the array equal to length S marking the ranks to find @return the index who's value we should partition around; -1 if biasing won't work. */ public static int biasedPartition( int[] S, int p, int r, int[] ks ){ int n = r - p + 1; int rank = p; while ( ks[ rank ] != 1 ) rank++; /* THIS GENERALLY ONLY ELIMINATES 1/7 MORE THAN MEDIAN; THIS COSTS 11 COMPARISON (WORST CASE); WE'LL SKIP ALL OF THIS IF N >= 77; THIS IS ACTUALLY PROBABLY BETTER THAN THAT ( SINCE 1/7 OF THE TIME IT ELIMINATES 2/7, AND SOMETIMES TAKES LESS THAN 11 COMPARISONS ) BUT WE'LL USE 77 AS THE CUT OFF POINT FOR NOW. */ if ( n <= 77 ) return -1 ; pl( "n = " + n ); pl( "rank = " + rank ); //-- FIGURE OUT WHICH 1/14 WE ARE IN int dist = Math.abs( rank - p ); double chunksize = n / 14.0; int chunk = 1; pl( "dist = " + dist ); pl( "chunksize = " + chunksize ); while ( ( chunk * chunksize ) < dist ) chunk++; if ( chunk > 14 ) chunk = 14; //just in case of weird things with //doubles and actually being the LAST rank //INVARIANT: chunk should now be between 1..14 pl( "chunk = " + chunk ); //-- GET SEVEN RANDOM INDEXES // the size of the section int size = ( r - p ) + 1; // for checking to see if we have picked this index before boolean range[] = new boolean[ size ]; // mark each number as not used for( int i = 0; i < size; i++ ) { range[ i ] = false; } // how many numbers are we finding int seven[] = new int[ 7 ]; // find the 7 indexes for( int i = 0; i < 7; i++ ) { int temp = p + ( int )( Math.random() * ( double )size ); while( range[ temp - p ] ) { temp = p + ( int )( Math.random() * ( double )size ); } seven[ i ] = temp; range[ temp - p ] = true; } //-- CHOOSE WHICH OF THE SEVEN RANDOM ELEMENTS TO PARTITION AROUND -- int whichseven = 0; switch ( chunk ){ case 1: { whichseven = 2; break;} case 2: case 3:{ whichseven = 3; break;} case 12: case 13:{ whichseven = 5; break;} case 14:{ whichseven = 6; break;} default: whichseven = -1; //MARKER FOR ``BAD'' BREAK -- NO BIAS USED } int returnIndex = -1;//MARKER FOR ``BAD'' BREAK -- NO BIAS USED //we have a "good" break -- bias it! if ( whichseven > 0 ) { //--MAKE INTPAIRS -- intPair[] sevenpairs = new intPair[ seven.length ]; intPair t = null; for ( int i = 0; i < seven.length; i++ ){ t = new intPair( seven[ i ] , S[ seven[i] ] ); sevenpairs[ i ] = t; } returnIndex = selectRank( sevenpairs, whichseven ); }//if whichseven > 0 return returnIndex; } /** For debugging output. */ private static void pl( String args ){ // System.out.println( args ); } //ARIS'S CODE: /** Given 7 numbers pick a certain rank using very few compares. @param pairs the numbers to compare @param neededRank the rank we are trying to find @return the index in the original array for the specified rank */ private static int selectRank( intPair[] pairs, int neededRank ){ intPair ip=null; //used in 3,5 switch(neededRank){ case 6: { HiBuildHeap(pairs); FindQuantiles.incComp( 1 ); if( pairs[1].v > pairs[2].v ){ return pairs[1].i; } else { return pairs[2].i; } // break; } case 5: { HiBuildHeap(pairs); // pl( ip2s( pairs ) ); //GET THIRD LARGEST IN HEAP int next = 0; boolean last = false; FindQuantiles.incComp( 1 ); last = ( pairs[1].v > pairs[2].v ) ; ip = ( last ) ? pairs[2] : pairs[1]; next = ( last ) ? 3 : 5; //children of the OTHER node //children of above FindQuantiles.incComp( 1 ); FindQuantiles.incComp( 1 ); ip = ( ip.v > pairs[ next ].v ) ? ip : pairs[ next ]; ip = ( ip.v > pairs[ next + 1 ].v ) ? ip : pairs[ next + 1]; return ip.i; // break; } case 3: { LoBuildHeap(pairs); // pl( "Inverted: "); // pl( ip2s( pairs ) ); int next = 0; boolean last; FindQuantiles.incComp( 1 ); last=(pairs[1].v < pairs[2].v); ip = ( last ) ? pairs[2] : pairs[1]; next = ( last ) ? 3 : 5; //children of the OTHER node //children of above FindQuantiles.incComp( 1 ); FindQuantiles.incComp( 1 ); ip = ( ip.v < pairs[ next ].v ) ? ip : pairs[ next ]; ip = ( ip.v < pairs[ next + 1 ].v ) ? ip : pairs[ next + 1]; return ip.i; // break; } case 2: { LoBuildHeap(pairs); FindQuantiles.incComp( 1 ); if( pairs[1].v > pairs[2].v){ return pairs[2].i; } else{ return pairs[1].i; } // break; } default: // This should never happen // RunTimeException( "ERROR DEEP IN FINDRANK // (selectRank called with " + neededRank + " )"); return(-1); } // return -1; } /** Swap the data at two different indexes in the array. @param pairs the array to swap values in @param a the index to swap b with @param b the index to swap a with */ private static void SwapIndex(intPair[] pairs, int a, int b){ intPair t=pairs[a]; pairs[a]=pairs[b]; pairs[b]=t; } // This is almost directly from the book /** Heapify an array of numbers based around index i. @param pairs the array to heapify @param i the index to heapify around */ private static void Heapify( intPair[] pairs, int i ){ int largest=i; if(2*i+1 < pairs.length){ FindQuantiles.incComp( 1 ); if( pairs[i].v < pairs[2*i].v ){ largest=2*i; } FindQuantiles.incComp( 1 ); if(pairs[largest].v < pairs[2*i+1].v){ largest=2*i+1; } if(i != largest){ SwapIndex(pairs,i,largest); Heapify(pairs,largest); } } } /** Heapify placing the smallest value at the top. @param pairs the array to inverse heapify @param i the index to reverse heapify around */ private static void InverseHeapify( intPair[] pairs, int i ){ int smallest=i; if(2*i+1 < pairs.length){ FindQuantiles.incComp( 1 ); if( pairs[i].v > pairs[2*i].v ){ smallest=2*i; } FindQuantiles.incComp( 1 ); if(pairs[smallest].v > pairs[2*i+1].v){ smallest=2*i+1; } if(i != smallest){ SwapIndex(pairs,i,smallest); Heapify(pairs,smallest); } } } /** Build a heap with the smallest value on top. @param pairs the array to build into a heap */ private static void LoBuildHeap( intPair[] pairs ){ int i=0,j=0; intPair[] NewPairs= new intPair[pairs.length+1]; for(j=0 ; j=1 ; i--){ InverseHeapify(NewPairs,i); } for(j=0 ; j=1 ; i--){ Heapify(NewPairs,i); } for(j=0 ; j