 interface Comparator {
  /** return < 0 for less, 0 for equal, > 0 for greater **/
  public int compare(Object a, Object b);
}

// sample implementation
 class StringComparator implements Comparator {
  public int compare(Object a, Object b) {
    if (!(a instanceof String && b instanceof String))
      throw new Error("Incompatable types in compare?");
    String x = (String) a;
    String y = (String) b;
    return x.compareTo(y);
  }
}


class SortableArray {
  protected Object array_[]; // the elements
  protected int count_;      // number of slots actually used
  // ... other methods omitted ...

  public void sort(Comparator cmp) { quickSort(0, count_ - 1, cmp); }

  protected void quickSort(int lo, int hi, Comparator cmp) {

    if (lo >= hi) return;

    //  Use median-of-three(lo, mid, hi) to pick a partition. 
    //  Also swap them into relative order while we are at it.
  
    int mid = (lo + hi) / 2;
  
    if (cmp.compare(array_[lo], array_[mid]) > 0) 
      swap(lo, mid);
    if (cmp.compare(array_[mid], array_[hi]) > 0) {
      swap(mid, hi);
      if (cmp.compare(array_[lo], array_[mid]) > 0) 
        swap(lo, mid);
    }
    
    int left = lo+1;           // start one past lo since already handled lo
    int right = hi-1;          // similarly
    if (left >= right) return; // if three or fewer we are done
    
    Object partition = array_[mid];
    
    for (;;) {
      
      while (cmp.compare(array_[right], partition) > 0) 
        --right;
      
      while (left < right && cmp.compare(array_[left], partition) <= 0) 
        ++left;
      
      if (left < right) {
        swap(left, right);
        --right;
      }
      else break;

    }
    
    quickSort(lo, left, cmp);
    quickSort(left+1, hi, cmp);
    
  }

  /* swap array_[i] and array_[j] */
  protected final void swap(int i, int j) { 
    Object tmp = array_[i]; 
    array_[i] = array_[j]; 
    array_[j] = tmp; 
  }

  // a sample extended version with a couple of coding tweaks:
  //   (1) Use a stack instead of recursive calls
  //   (2) hard-code swaps instead of calling swap method

  // Since the largest half is always chosen to be pushed, there can be
  // no more than lg N + 1 pushed halves. Given that indexes
  // are signed 32 bits, there can be no more than 2^31 elements. So:

  static final int STACK_SIZE = 64; // for 32 bit int indices

  protected void quickSortV2(int lo, int hi, Comparator cmp) {
    int[] stack = new int[STACK_SIZE];
    int sp = 0;

    if (lo >= hi) return;
    
    for (;;) {

      //  Use median-of-three(lo, mid, hi) to pick a partition. 
      //  Also swap them into relative order while we are at it.
      
      int mid = (lo + hi) / 2;
      
      if (cmp.compare(array_[lo], array_[mid]) > 0) {
        Object t = array_[lo]; array_[lo] = array_[mid]; array_[mid] = t;
      }
      if (cmp.compare(array_[mid], array_[hi]) > 0) {
        Object t = array_[mid]; array_[mid] = array_[hi]; array_[hi] = t;
        if (cmp.compare(array_[lo], array_[mid]) > 0) {
          Object u = array_[lo]; array_[lo] = array_[mid]; array_[mid] = u;
        }
      }
      
      int left = lo+1;           // start one past lo since already handled lo
      int right = hi-1;          // similarly
      
      if (left >= right) {       // done, pop new ones
        if (sp > 0) {
          lo = stack[--sp];
          hi = stack[--sp];
        }
        else 
          return;
      }
      else {
        Object partition = array_[mid];
        
        for (;;) {
          
          while (cmp.compare(array_[right], partition) > 0) {
            --right;
          }
          
          while (left < right && cmp.compare(array_[left], partition) <= 0) {
            ++left;
          }
          
          if (left < right) {
            Object t = array_[left]; array_[left] = array_[right]; array_[right] = t;
            --right;
          }
          else
            break;
        }
        
        right = left + 1; // force to be first of right side

        // iterate the smaller side; push larger
        // note that given above code at least one side must have > 1 element

        if (right >= hi) // if empty, ignore
          hi = left;
        else if (lo >= left)
          lo = right;
        else if (left - lo > hi - right) {
          stack[sp++] = left;
          stack[sp++] = lo;
          lo = right;
        }
        else {
          stack[sp++] = hi;
          stack[sp++] = right;
          hi = left;
        }
      }
    }
  }

  // another sample extended version with a couple of coding tweaks:
  //   (1) Use iteration instead of recursive call for one side
  //   (2) Exit after one pass if they are all in order
  //   (3) Use insertion sort for small subsets
  //   (4) hard-code swaps instead of calling swap method

  static final int INSERTION_SORT_THRESHOLD = 8;

  protected void quickSortV3(int lo, int hi, Comparator cmp) {

    while (lo < hi) {

      // Simultaneously check if in order and, if small use insertion sort
      boolean useInsertion = (hi - lo + 1) <= INSERTION_SORT_THRESHOLD;
      int i = lo + 1;
      for (;;) {
        Object x = array_[i];
        int k = i - 1;
        while (k >= lo && cmp.compare(x, array_[k]) < 0) {
          array_[k+1] = array_[k];
          --k;
        }
        array_[k+1] = x;

        if (i == hi) // done
          return;
        else if (!useInsertion && k + 1 != i) // if not in order use QS
          break;
        else
          ++i;
      }

      //  Use median-of-three(lo, mid, hi) to pick a partition. 
      //  Also swap them into relative order while we are at it.
      
      int mid = (lo + hi) / 2;
      
      if (cmp.compare(array_[lo], array_[mid]) > 0) {
        Object t = array_[lo]; array_[lo] = array_[mid]; array_[mid] = t;
      }
      if (cmp.compare(array_[mid], array_[hi]) > 0) {
        Object t = array_[mid]; array_[mid] = array_[hi]; array_[hi] = t;
        if (cmp.compare(array_[lo], array_[mid]) > 0) {
          Object u = array_[lo]; array_[lo] = array_[mid]; array_[mid] = u;
        }
      }
      
      int left = lo+1;           // start one past lo since already handled lo
      int right = hi-1;          // similarly
      if (left >= right) return; // if three or fewer we are done

    
      Object partition = array_[mid];

      for (;;) {
        
        while (cmp.compare(array_[right], partition) > 0) 
          --right;
        
        while (left < right && cmp.compare(array_[left], partition) <= 0) 
          ++left;
        
        if (left < right) {
          Object t = array_[left]; array_[left] = array_[right]; array_[right] = t;
          --right;
        }
        else break;
      }

      // iterate the smaller side; recurse on larger
      if (left - lo > hi - left) {
        if (lo < left) quickSortV3(lo, left, cmp);
        lo = left + 1;
      }
      else {
        if (left+1 < hi) quickSortV3(left+1, hi, cmp);
        hi = left;
      }

    }
    
  }

}



  

