import java.util.Vector; // These are extended vectors import rebelsky.util.Comparable; // We need to compare elements import rebelsky.util.IncomparableException; // Some things can't be compared import rebelsky.util.StringUtils; // For the "animated" version import rebelsky.io.SimpleOutput; // For the "animated" version /** * An extension of java.util.Vector that supports an * additional quicksort method that sorts the current * vector. Written as part of a laboratory for CS152. * Copyright (c) 1998 Samuel A. Rebelsky and YOUR NAME HERE. * All rights reserved. * * @author Samuel A. Rebelsky * @author YOUR NAME HERE * @version 1.0 of March 1998 */ public class QuicksortableVector extends Vector { // +-----------+--------------------------------------------------------- // | Variables | // +-----------+ /** * The number of steps in the last call to quicksort. */ protected int steps; /** * Where does output go? If this is not set to null, produces * an "animation" of sorting to the output channel. Otherwise, * does not produce any output when sorting. */ SimpleOutput out; /** * The width of the widest entry in the vector. Used only when * printing the animation. */ int width; // +--------------+------------------------------------------------------ // | Constructors | // +--------------+ /** * Create a new empty vector. */ public QuicksortableVector() { super(); out = null; width = -1; } // QuicksortableVector() /** * Construct an empty vector with the specified initial capacity. */ public QuicksortableVector(int initial_capacity) { super(initial_capacity); out = null; width = -1; } // QuicksortableVector(int) /** * Construct a new vector with specified initial capacity and * capacity increment. */ public QuicksortableVector(int initial_capacity, int increment) { super(initial_capacity, increment); out = null; width = -1; } // QuicksortableVector // +------------------+-------------------------------------------------- // | Exported Methods | // +------------------+ /** * Sort the current vector. * pre: All the elements of the current vector are Comparable * and can be compared to each other. * post: The elements are in order. * * @exception IncomparableException * when two elements can't be compared. */ public void quickSort() throws IncomparableException { // Indicate that we've spent 0 steps on this process. steps = 0; // No "animation" this.out = null; // Quicksort all the elements of the vector quickSort(0, size()-1); } // quickSort() /** * Sort the current vector. Describe the steps as we go to the * given output. See the other version for pre and postconditions. */ public void quickSort(SimpleOutput out) throws IncomparableException { // Indicate that we've spent 0 steps on this process. steps = 0; // Set up output this.out = out; // Determine the maximum width of any cell for (int i = 0; i < size(); ++i) { int new_width = elementAt(i).toString().length(); if (width < new_width) { width = new_width; } } // for width = width + 2; // Quicksort all the elements of the vector quickSort(0, size()-1); // Print the sorted vector printSubvector(0, size()-1); out.println(); // And restore the animation stuff out = null; width = -1; } // QuicksortableVector // +---------------+----------------------------------------------------- // | Local Methods | // +---------------+ /** * Partition a subvector vector based on a pivot (which must be * in the subvector. While determining that the pivot is at * position P, this method ensures that all the elements smaller * than or equal to the pivot precede the pivot, and all elements * larger than the pivot follow the pivot. * pre: 0 <= lb <= ub < size() * post: for all i, lb <= i <= P, for all j, P < j <= ub, * elementAt(i) <= elementAt(j) * @exception IncomparableException * When two elements can't be compared. */ protected int partition(Comparable pivot, int lb, int ub) throws IncomparableException { /* * We'll use two indices into the subvector, one to the * "larger" half, one to the "smaller" half. Both begin * at the far end of their presumed section. We advance * each toward the center over correctly placed elements * until they cross or hit incorrectly placed elements. * When both are over incorrectly placed elements, we swap. */ // The index of the pivot int pivot_loc = -1; // The index into the larger elements. int larger = ub; // The index into the smaller elements. int smaller = lb; // Keep going until we cross. Throw an exception if we ever hit // an invalid type. try { while (smaller < larger) { // Move the larger index towards the middle as much as is possible. // The casting of the element to Comparable is caught outside the // while loop. while ( (larger >= lb) && (pivot.lessThan(((Comparable) elementAt(larger)))) ) { larger = larger - 1; } // while ( pivot < elementAt(larger) ) // Move the smaller index towards the middle as much as possible. while ( (smaller <= ub) && (!pivot.lessThan(((Comparable) elementAt(smaller)))) ) { if (pivot.equals(elementAt(smaller))) { pivot_loc = smaller; } smaller = smaller + 1; } // while ( pivot >= elementAt(smaller) ) // Swap if necessary if (smaller < larger) { swap(smaller,larger); } // if } // while (smaller < larger) } // try catch (ClassCastException e) { throw new IncomparableException(); } // catch // At this point, we know that smaller points to the beginning of // the large element and larger points to the end of the small // elements. We want to put the pivot at that position and then // return that position. swap(pivot_loc, larger); return larger; } // partition(Comparable, int, int) /** * Pick a pivot. Analyses I've seen suggest that the second * element works better than the first. The use of a separate * method lets us experiment. * pre: 0 <= lb < ub < size() * post: some element in the range [lb .. ub] is returned * * @exception IncomparableException * when the selected pivots is not Comparable */ protected Comparable pickPivot(int lb, int ub) throws IncomparableException { try { return (Comparable) elementAt(lb+1); } catch (Exception e) { throw new IncomparableException(); } } // pickPivot(int, int) /** * Print a subvector. Does not indent by the appropriate amount. */ protected void printSubvector(int lb, int ub) { // If there are no cells, stop if (ub < lb) return; // Print an intitial separator out.print("|"); // Print all the cells followed by a separator for (int i = lb; i <= ub; ++i) { out.print(StringUtils.center(elementAt(i).toString(), width) + "|"); } } // printSubvector /** * Sort a subrange of the current vector (all elements between * lb and ub inclusive). * pre: All the elements in the subrange are Comparable * and can be compared to each other. * pre: 0 <= lb, ub < size() * post: The elements in the range [lb .. ub] are in order. * * @exception IncomparableException * when two elements can't be compared. */ protected void quickSort(int lb, int ub) throws IncomparableException { // Observe that we've spent an additional step steps = steps + 1; // If we're animating, print the vector if ((out != null) && (lb <= ub)) { out.print(StringUtils.spaces((width+1)*lb)); printSubvector(lb, ub); out.println(); } // Base case: subrange of length 0 or 1. if (ub <= lb) return; // Identify a pivot. This pivot must be in the vector. Comparable pivot = pickPivot(lb,ub); // Partition the subvector based on that pivot. This pivot must // be in the vector. The function returns the position of the // pivot. int pivot_loc = partition(pivot, lb, ub); // If we're animating, print the partitioned vector if (out != null) { out.print(StringUtils.spaces((width+1)*pivot_loc+1)); out.print("*"); out.print(StringUtils.center(elementAt(pivot_loc).toString(), width-2)); out.print("*"); out.println(); } // if we're animating // Sort the two subvectors. It's important that we be able to // shrink at least one of the subvectors by at least one element, // otherwise we may never stop (e.g., when all the elements are // the same). quickSort(lb, pivot_loc-1); quickSort(pivot_loc+1,ub); // No need to merge, as we've been doing everything in place } // quickSort(int,int) /** * Swap two elements of the vector. * pre: 0 <= alpha, beta < size() * post: the element at alpha and the element at beta have * swapped positions. */ protected void swap(int alpha, int beta) { Object tmp = elementAt(alpha); setElementAt(elementAt(beta), alpha); setElementAt(tmp, beta); } // swap(int, int) } // QuicksortableVector