My Sorters

import java.util.*;

class IntegerComparator implements Comparator<Integer> {
    public int cmpCount = 0;
    public int compare(Integer a, Integer b) {
        ++cmpCount;
        return a - b;
    }
}

public class MySorters {
    
    /* Private Values */
    
    private static boolean tryToReduceSwaps = true;
    private static boolean useMiddleAsPivot = true;
    private static boolean compoundPivot = true;
    private static int swapCount = 0;
    private static int cmp2Count = 0;
    private static IntegerComparator comparator = new IntegerComparator();

    /* Quicksort Method */
    
    public static void quicksort(Integer[] array, int lower, int upper) {
        if (upper - lower < 2) return;
        int[] p = partition(array, lower, upper);
        quicksort(array, lower, p[0]);
        quicksort(array, p[1] + 1, upper);
    }
    
    /* Quicksort Functions */
    
    private static int[] partition(Integer[] array, int lower, int upper) {
        
        // Variable Declarations
        int iVal, jVal; // Values at indices i and j.
        int cmpVal; // The result of a comparison.
        boolean equalsPivot, needsToMove;
        int[] p = new int[2]; // Array of left and right pivot boundaries.
        
        // Pivot Initialization
        int pivotIndex = getPivotIndex(array, lower, upper);
        p[0] = pivotIndex; // An index defining the pivot's left boundary.
        p[1] = pivotIndex; // An index defining the pivot's right boundary.
        final int pVal = array[pivotIndex]; // The pivot value.

        // We begin with values of i and j that are indices immediately to the
        // left of and to the right of the pivot index respectively. From there
        // we decrement i (moving i toward lower), and we increment j (moving j
        // toward upper).
        //
        // Note: We cannot begin with i equal to lower and j equal to upper (or
        // upper - 1) and move i and j toward the pivot. Why not? Exercise: Try
        // it, and find a sequence to sort that exposes the problem.
        int i = pivotIndex - 1, j = pivotIndex + 1;
        
        // For each iteration of the following optional while loop, we will
        // exchange a value at position i that is greater than the pivot value
        // with a value at position j that is less than the pivot value, or we
        // will break out of the loop, either because the value of i is les
        // than lower or because the value of j is equal to upper.
        while (tryToReduceSwaps) {
            // The following while loop has the effect of decrementing i until
            // it is either the index of a value that is greater than the pivot
            // value or it is less than lower. In the process, any values
            // (corresponding to the current value of i) that are equal to the
            // pivot value are merged with the pivot if the value of
            // compoundPivot is true.
            while (ge2(i, lower) && le1(iVal = array[i], pVal)) {
                // If the value at index i is equal to the pivot value and
                // the pivot can span more than one element in the array
                // (i.e. compoundPivot is true), then merge the value at
                // index i with the pivot.
                if (compoundPivot && eq1(iVal, pVal)) {
                    // If the value at index i is not immediately to the left
                    // of the pivot, then move it there, by swapping it with
                    // the value that is to the left of the pivot.
                    if (ne2(i, p[0] - 1)) {
                        swap(array, i, p[0] - 1);
                    }
                    --p[0]; // Decrease the pivot's left boundary.
                }
                --i;
            }
            // The following while loop has the effect of incrementing j until
            // it is either the index of a value that is less than the pivot
            // value or it is equal to upper. In the process, any values
            // (corresponding to the current value of j) that are equal to the
            // pivot value are merged with the pivot if the value of
            // compoundPivot is true.
            while (lt2(j, upper) && ge1(jVal = array[j], pVal)) {
                // If the value at index j is equal to the pivot value and
                // the pivot can span more than one element in the array
                // (i.e. compoundPivot is true), then merge the value at
                // index j with the pivot.
                if (compoundPivot && eq1(jVal, pVal)) {
                    // If the value at index j is not immediately to the right
                    // of the pivot, then move it there, by swapping it with
                    // the value that is to the right of the pivot.
                    if (ne2(j, p[1] + 1)) {
                        swap(array, j, p[1] + 1);
                    }
                    ++p[1]; // Increase the pivot's right boundary.
                }
                ++j;
            }
            // If the value of i is less than lower or the value of j equals
            // upper, then there are no more pairs of elements to the left of
            // and to the right of the pivot that need to be moved and can
            // therefore be swapped; hence, we break out of the outer while
            // loop and proceed to the next part of the partitioning algorithm.
            if (lt2(i, lower) || eq2(j, upper)) {
                break;
            }
            // Otherwise, the values of i and j identify values that need to be
            // moved to opposite sides of the pivot, so we swap the two values.
            // Then we decrement i, increment j, and repeat.
            else {
                swap(array, i, j);
                --i;
                ++j;
            }
        }
        // We (continue to) decrement i, moving the value of i toward lower until
        // the value of i is less than lower. At that point, all the values that
        // were originally to the left of the pivot when partition was involked
        // and were greater than the pivot value will have been moved to the right
        // of the pivot.
        while (ge2(i, lower)) {
            cmpVal = cmp1(array[i], pVal);
            equalsPivot = cmpVal == 0;
            needsToMove = cmpVal > 0;
            // If the value at position i is equal to the pivot value and the pivot
            // may contain multiple elements (compoundPivot is true), or if the
            // value at position i is greater than the pivot value, then the value
            // might need to be moved and at least one pivot boundary will need to
            // be adjusted.
            if ((compoundPivot && equalsPivot) || needsToMove) {
                // If i is not the index of the element immediate to the left of 
                // the pivot, then we need to swap the value at that position with
                // the value at index i.
                if (ne2(i, p[0] - 1)) {
                    swap(array, i, p[0] - 1);
                }
                // If the value at index i needs to move to the other side of the
                // pivot, then swap the value with the pivot's right boundary and
                // decrement the right boundary.
                if (needsToMove) {
                    swap(array, p[0] - 1, p[1]);
                    --p[1];
                }
                // Decrement the pivot's left boundary.
                --p[0];
            }
            --i;
        }
        // We (continue to) increment j, moving the value of j toward upper until
        // the value of j is equal to upper. At that point, all the values that
        // were originally to the right of the pivot when partition was involked
        // and were less than the pivot value will have been moved to the left
        // of the pivot.
        while (lt2(j, upper)) {
            cmpVal = cmp1(array[j], pVal);
            equalsPivot = cmpVal == 0;
            needsToMove = cmpVal < 0;
            // If the value at position j is equal to the pivot value and the pivot
            // may contain multiple elements (compoundPivot is true), or if the
            // value at position j is less than the pivot, then the value might need
            // to be moved and at least one pivot boundary will need to be adjusted.
            if ((compoundPivot && equalsPivot) || needsToMove) {
                // If j is not the index of the element immediate to the right of 
                // the pivot, then we need to swap the value at that position with
                // the value at index j.
                if (ne2(j, p[1] + 1)) {
                    swap(array, p[1] + 1, j);
                }
                // If the value at index j needs to move to the other side of the
                // pivot, then swap the value with the pivot's left boundary and
                // increment the right boundary.
                if (needsToMove) {
                    swap(array, p[1] + 1, p[0]);
                    ++p[0];
                }
                // Increment the pivot's right boundary.
                ++p[1];
            }
            ++j;
        }
        // Return the array of pivot boundaries.
        return p;
    }
    private static int getPivotIndex(Integer[] array, int lower, int upper) {
        return useMiddleAsPivot ? lower + ((upper - lower) / 2) : lower;
    }
    
    /* Compare Utilities */
    
    private static int cmp1(int a, int b) {
        return comparator.compare(a, b);
    }
    private static int cmp2(int a, int b) {
        ++cmp2Count;
        return a - b;
    }
    private static boolean eq1(int a, int b) { return cmp1(a, b) == 0; }
    private static boolean ne1(int a, int b) { return cmp1(a, b) != 0; }
    private static boolean gt1(int a, int b) { return cmp1(a, b) > 0; }
    private static boolean ge1(int a, int b) { return cmp1(a, b) >= 0; }
    private static boolean lt1(int a, int b) { return cmp1(a, b) < 0; }
    private static boolean le1(int a, int b) { return cmp1(a, b) <= 0; }
    private static boolean eq2(int a, int b) { return cmp2(a, b) == 0; }
    private static boolean ne2(int a, int b) { return cmp2(a, b) != 0; }
    private static boolean gt2(int a, int b) { return cmp2(a, b) > 0; }
    private static boolean ge2(int a, int b) { return cmp2(a, b) >= 0; }
    private static boolean lt2(int a, int b) { return cmp2(a, b) < 0; }
    private static boolean le2(int a, int b) { return cmp2(a, b) <= 0; }
    
    /* Array Utilities and Functions */
    
    private static void swap(Integer[] array, int i, int j) {
        ++swapCount;
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
    private static Integer[] copy(Integer[] array) {
        final int len = array.length;
        Integer[] copyOfArray = new Integer[len];
        for (int i = 0; i < len; i++) {
            copyOfArray[i] = array[i];
        }
        return copyOfArray;
    }
    private static void printArray(Integer[] array) {
        for (Integer i : array) {
            System.out.print(i);
            System.out.print(" ");
        }
        System.out.println();
    }
    private static void customSort(Integer[] array) {
        resetStats();
        System.out.println("\nQuicksort");
        quicksort(array, 0, array.length);
        printArray(array);
        printStats();
    }
    private static void librarySort(Integer[] array) {
        resetStats();
        System.out.println("\nArrays.sort (Timsort)");
        Arrays.sort(array, comparator);
        printArray(array);
        printStats();
    }
    
    /* Stats Functions */
    
    private static void resetStats() {
        comparator.cmpCount = cmp2Count = swapCount = 0;
    }
    private static void printStats() {
        System.out.println("tryToReduceSwaps: " + tryToReduceSwaps);
        System.out.println("useMiddleAsPivot: " + useMiddleAsPivot);
        System.out.println("compoundPivot: " + compoundPivot);
        System.out.println("swap: " + swapCount);
        System.out.println("cmp1: " + comparator.cmpCount);
        System.out.println("(cmp2: " + cmp2Count + ")");
    }
    
    /* Main Method */
    
    public static void main(String args[]) {
        final int n = args.length;
        final int count = n > 0 ? Integer.parseInt(args[0]) : 10;
        final int max = n > 1 ? Integer.parseInt(args[1]) : 10;
        final Integer[] array = new Integer[count];
        for (int i = 0; i < count; ++i) {
            array[i] = (int)Math.floor(Math.random() * max);
        }
        System.out.println("Unsorted");
        printArray(array);
        
        System.out.println("\nSorted");
        useMiddleAsPivot = false;
        tryToReduceSwaps = false;
        compoundPivot= false;
        customSort(copy(array));
        
        useMiddleAsPivot = false;
        tryToReduceSwaps = false;
        compoundPivot= true;
        customSort(copy(array));
        
        useMiddleAsPivot = false;
        tryToReduceSwaps = true;
        compoundPivot= true;
        customSort(copy(array));
        
        useMiddleAsPivot = true;
        tryToReduceSwaps = true;
        compoundPivot= true;
        customSort(copy(array));
        
        librarySort(copy(array));
    }
}