/* An instance of this Java class has methods by which to rearrange the ** elements of an array, each of which is classified as either RED or BLUE, ** so that the RED ones are in lower-numbered locations and the BLUE ones ** are in higher-numbered locations. ** Afterwards, it can report how many comparisons and how many swaps were ** performed in carrying out this task. ** To keep things simple, the array to be partitioned is of type char[] ** and each of its elements is assumed to have as its value one of 'R' ** or 'B' (standing for RED and BLUE, respectively.) ** ** Authors: R. McCloskey and < STUDENTS' NAMES > ** Known Flaws: ... */ public class RedBluePartitioner { // class constants // --------------- private final char RED = 'R'; private final char BLUE = 'B'; // instance variables // ------------------ // The value of this variable indicates the location of the RED/BLUE // boundary in the array most recently partitioned. Specifically, // letting ary[] be that array, 'blueStart' satisfies the condition // that all elements in ary[0 .. blueStart) are RED and all elements in // ary[blueStart .. ary.length) are BLUE. private int blueStart; // # of comparisons and # of swaps performed during most // recent execution of either partition1() or partition2(). private int compareCntr; private int swapCntr; // constructors // ------------ // No constructor needed // observers // --------- /* Returns, with respect to the array most recently partitioned, ** the location at which the BLUE segment begins. */ public int blueStart() { return blueStart; } /* Returns the # of comparisons performed during the most recent ** execution of a method that does partitioning. */ public int numComparisons() { return compareCntr; } /* Returns the # of swaps performed during the most recent ** execution of a method that does partitioning. */ public int numSwaps() { return swapCntr; } // mutators // -------- /* Rearranges the elements of ary[] (the given array) so that all RED ** values come before any BLUE values. The code is consistent with ** a loop invariant specifying that the ?-segment lies between the ** RED and BLUE segments. In diagram form (using 'qS', 'bS', and 'N' as ** abbreviations, respectively, for 'qStart', 'blueStart', and 'ary.length'), ** the loop invariant is ** ** 0 qS bS N ** +-----------+-------------+--------------+ ** ary | all RED | ? | all BLUE | ** +-----------+-------------+--------------+ */ public void partition1(char[] ary) { // reset variables that keep track of # comparisons and swaps. compareCntr = 0; swapCntr = 0; // Initialize variables so as to truthify the loop invariant // (by making the ?-segment cover the whole array). int qStart = 0; // where ?-segment begins (local variable) blueStart = ary.length; // where BLUE-segment begins (instance variable) /* loop invariant: ** 0 <= qStart <= blueStart <= ary.length && ** segmentIsRed(ary,0,qStart) && ** segmentIsBlue(ary,blueStart,ary.length) */ // Verify that the loop invariant is true before 1st iteration. assert loopInvariant1(ary, qStart, blueStart); while (qStart != blueStart) { // Examine one array element and take appropriate action according // to its color. An appropriate action preserves the truth of the // loop invariant and makes progress towards termination of the loop. if (isRed(ary[-99])) { // <<<<--- NEEDS MODIFICATION // MISSING CODE } else { // MISSING CODE } // Verify that the loop invariant is true now (at iteration's end). assert loopInvariant1(ary, qStart, blueStart); } // end of loop body } // end of partition1() /* Returns true if and only if 0 <= k <= m <= a.length && ** all elements in a[0..k) are RED and ** all elements in a[m..a.length) are BLUE. */ private boolean loopInvariant1(char[] a, int k, int m) { return 0 <= k && k <= m && m <= a.length && segmentIsRed(a,0,k) && segmentIsBlue(a,m,a.length); } /* Rearranges the elements of ary[] (the given array) so that all RED ** values come before any BLUE values. The code is consistent with ** a loop invariant specifying that the ?-segment precedes the RED ** segment (which precedes the BLUE segment). In diagram form (using ** 'rS', 'bS', and 'N' as abbreviations, respectively, for 'redStart', ** 'blueStart', and 'ary.length'), the loop invariant is ** ** 0 rS bS N ** +-----------+-------------+--------------+ ** ary | ? | all RED | all BLUE | ** +-----------+-------------+--------------+ */ public void partition2(char[] ary) { // reset variables that keep track of # comparisons and swaps. compareCntr = 0; swapCntr = 0; // Initialize variables so as to truthify the loop invariant // (by making the ?-segment cover the whole array). int redStart = -99; // where RED segment begins (local variable) blueStart = -99; // where BLUE segment begins (instance var) // ^^^^^^ NEEDS MODIFICATION // Verify that the loop invariant is true before 1st iteration. assert loopInvariant2(ary, redStart, blueStart); while ( true ) { // <<<<<--- LOOP GUARD NEEDS MODIFICATION // Examine one array element and take appropriate action according // to its color. An appropriate action preserves the truth of the // loop invariant and makes progress towards termination of the loop. // MISSING CODE // Verify that the loop invariant is true now (at iteration's end). assert loopInvariant2(ary, redStart, blueStart); } // end of loop body } // end of partition2() /* Returns true if and only if 0 <= k <= m <= a.length && ** all elements in a[k..m) are RED and ** all elements in a[m..a.length) are BLUE. */ private boolean loopInvariant2(char[] a, int k, int m) { return 0 <= k && k <= m && m <= a.length && segmentIsRed(a,-99,-99) && segmentIsBlue(a,-99,-99); // ^^^^^^^ ^^^^^^^^ // NEEDS MODIFICATION } // ------------------------------------------------------------ // utility methods // --------------- /* Methods that classify a character as being either RED or BLUE. ** They also increment the comparison counter. */ private boolean isRed(char ch) { compareCntr++; return ch == RED; } private boolean isBlue(char ch) { compareCntr++; return ch == BLUE; } /* Swaps the values at the specified locations (i and j) in the ** specified array (a). Also increments the swap counter. ** pre: 0 <= i < a.length && 0 <= j < a.length */ private void swap(char[] a, int i, int j) { swapCntr++; char temp = a[i]; a[i] = a[j]; a[j] = temp; } /* Returns true iff every element in the specified array segment ** (namely, a[lower..upper)) is equal to the specified value (ch). */ private boolean allEqualTo(char[] a, int lower, int upper, char ch) { int i = lower; // loop invariant: 0<=lower<=i<=upper<=a.length && // every element in a[lower..i) is equal to ch while (i != upper && a[i] == ch) { i = i+1; } return i == upper; } /* Returns true iff every element in the specified array segment ** (namely, a[lower..upper)) is RED. ** pre: 0 <= lower <= upper <= a.length */ private boolean segmentIsRed(char[] a, int lower, int upper) { return allEqualTo(a, lower, upper, RED); } /* Returns true iff every element in the specified array segment ** (namely, a[lower..upper)) is BLUE. ** pre: 0 <= lower <= upper <= a.length */ private boolean segmentIsBlue(char[] a, int lower, int upper) { return allEqualTo(a, lower, upper, BLUE); } }