Pages

Pretty Quick Sorters

import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;

interface Counter { int count(); }

interface CountingSorter<E>
{
    void sort(List<E> list);
    int exchangeCount();
    int comparisonCount();
}

interface Subsorter<E> { void sort(List<E> list, int lower, int upper); }

interface InjectableSorter<E> { void sort(List<E> list, Comparator<E> cmp); }

final class ListFactory<E>
{
    public final List<E> produce()
    {
        return new ArrayList<E>(); // or, new LinkedList<E>();
    }
}

class ListCopier<E>
{
    private final ListFactory<E> listFactory = new ListFactory<E>();
    
    public final List<E> copy(List<E> list)
    {
        List<E> copy = listFactory.produce();
        copy.addAll(list);
        return copy;
    }
}

final class ListPermuter<E>
{
    private final ListFactory<E> listFactory = new ListFactory<E>();
    private final ListCopier<E> listCopier = new ListCopier<E>();
    private final ListFactory<List<E>> listOfListsFactory = new ListFactory<List<E>>();

    public List<List<E>> allPermutationsOf(List<E> original)
    {
        List<E> list = listCopier.copy(original);
        List<List<E>> allPermutations = listOfListsFactory.produce();
        final int n = list.size();
        if (n <= 1)
        {
            List<E> singlePermutation = listCopier.copy(list);
            allPermutations.add(singlePermutation);
            return allPermutations;
        }
        for (int i = 0; i < n; i++)
        {
            E element = list.get(i);
            
            List<E> oneLess = listFactory.produce();
            for (int j = 0; j < n; j++)
                if (i != j)
                    oneLess.add(list.get(j));
                 
            for (List<E> permutation : allPermutationsOf(oneLess))
            {
                List<E> nextPermutation = listFactory.produce();
                nextPermutation.add(element);
                nextPermutation.addAll(permutation);
                allPermutations.add(nextPermutation);
            }
        }
        return allPermutations;
    }
}

final class Multitool<E>
{
    private final ListFactory<E> listFactory = new ListFactory<E>();
    private final ListCopier<E> listCopier = new ListCopier<E>();
    private final ListPermuter<E> listPermuter = new ListPermuter();
    private Long startTime = System.nanoTime();
    
    public final List<E> produce()
    {
        return listFactory.produce();
    }
    public final List<E> copy(List<E> list)
    {
        return listCopier.copy(list);
    }
    public final List<List<E>> allPermutationsOf(List<E> list)
    {
        return listPermuter.allPermutationsOf(list);
    }
    public final void startTimer()
    {
        startTime = System.nanoTime();
    }
    public final long stopTimer()
    {
        return System.nanoTime() - startTime;
    }
}

class CountingExchanger<E> implements Counter
{
    private int n = 0;
    public void exchange(List<E> list, int i, int j)
    {
        n++;
        E tmp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, tmp);
    }
    public int count() { return n; }
}

class CountingComparator<E> implements Comparator<E>, Counter
{
    private int n = 0;
    private Comparator<E> comparator;
    public CountingComparator(Comparator<E> cmp)
    {
        this.comparator = cmp;
    }
    public int compare(E e1, E e2)
    {
        n++;
        return comparator.compare(e1, e2);
    }
    public int count() { return n; }
}

class Pivoter<E>
{
    private final CountingExchanger<E> exchanger;
    private final CountingComparator<E> comparator;
    
    public Pivoter(Comparator<E> cmp)
    {
        this(new CountingExchanger<E>(), new CountingComparator<E>(cmp));
    }
    public Pivoter(CountingExchanger<E> exch, CountingComparator<E> cmp)
    {
        this.exchanger = exch;
        this.comparator = cmp;
    }
    public final int exchangeCount()
    {
        return exchanger.count();
    }
    public final int comparisonCount()
    {
        return comparator.count();
    }
    final public int pivotDown(List<E> list, int lower, int upper)
    {
        if (upper - lower <= 1) return -1;
        int pivot = upper - 1;
        final E pivotValue = list.get(pivot);
        int j = pivot - 1;
        for (int i = j; i >= lower; i--)
        {
            final int compareResult = comparator.compare(list.get(i), pivotValue);
            if (compareResult >= 0)
            {
                if (i < j) exchanger.exchange(list, i, j);
                if (compareResult > 0) exchanger.exchange(list, pivot, j);
                pivot = j--;
            }
        }
        return pivot;
    }
    public final int pivotUp(List<E> list, int lower, int upper)
    {
        if (upper - lower <= 1) return -1;
        int pivot = lower;
        final E pivotValue = list.get(pivot);
        int j = pivot + 1;
        for (int i = j; i < upper; i++)
        {
            final int compareResult = comparator.compare(list.get(i), pivotValue);
            if (compareResult <= 0)
            {
                if (i > j) exchanger.exchange(list, i, j);
                if (compareResult < 0) exchanger.exchange(list, pivot, j);
                pivot = j++;
            }
        }
        return pivot;
    }
    public final int pivotIn(List<E> list, int lower, int upper)
    {
        final int n = upper - lower - 1;
        if (n < 1) return -1;
        final E pivotValue = list.get((int)(Math.random() * n));
        int i = lower, j = upper - 1;
        int left = -1, right = -1;
        while (i < j)
        {
            if (left < 0)
            {
                if (comparator.compare(list.get(i), pivotValue) > 0)
                    left = i;
                else
                    i++;
            }
            if (right < 0)
            {
                if (comparator.compare(list.get(j), pivotValue) < 0)
                    right = j;
                else
                    j--;
            }
            if (left >= 0 && right >=0)
            {
                exchanger.exchange(list, left, right);
                left = right = -1;
            }
        }
        
        System.out.println("pivot index: " + i);

        if (left >= 0)
        {
            if (left < i - 1)
                exchanger.exchange(list, left, i - 1);
            exchanger.exchange(list, i - 1, i);
        }
        else if (right >= 0)
        {
            if (right > i + 1)
                exchanger.exchange(list, i + 1, right);
            exchanger.exchange(list, i, i + 1);
        }

        return i;
    }
}

abstract class AbstractQuicksorter<E> extends Pivoter<E> implements CountingSorter<E>
{
    protected AbstractQuicksorter(Comparator<E> cmp)
    {
        super(cmp);
    }
    public void sort(List<E> list)
    {
        introspectiveSort(list, 0, list.size());
    }
    public void pivotInSort(List<E> list)
    {
        pivotInSort(list, 0, list.size());
    }
    public void pivotDownSort(List<E> list)
    {
        pivotDownSort(list, 0, list.size());
    }
    public void pivotUpSort(List<E> list)
    {
        pivotUpSort(list, 0, list.size());
    }
    public void pivotUpDownSort(List<E> list)
    {
        pivotUpDownSort(list, 0, list.size());
    }
    public void pivotDownUpSort(List<E> list)
    {
        pivotDownUpSort(list, 0, list.size());
    }
    public abstract void introspectiveSort(List<E> list, int lower, int upper);
    public abstract void pivotDownSort(List<E> list, int lower, int upper);
    public abstract void pivotUpSort(List<E> list, int lower, int upper);
    public abstract void pivotInSort(List<E> list, int lower, int upper);
    public abstract void pivotDownUpSort(List<E> list, int lower, int upper);
    public abstract void pivotUpDownSort(List<E> list, int lower, int upper);
}

final class Quicksorter<E> extends AbstractQuicksorter<E>
{
    private final int TIP; // the too-tiny / not-too-tiny tipping point
    private final Subsorter<E> TOO_TINY;
    private final Subsorter<E> NOT_TOO_TINY;

    public Quicksorter(Comparator<E> cmp)
    {
        super(cmp);
        this.TIP = 4;
        this.TOO_TINY = (lst, low, high) -> pivotUpDownSort(lst, low, high);
        this.NOT_TOO_TINY = (lst, low, high) -> introspectiveSort(lst, low, high);
    }
    public Quicksorter(Comparator<E> cmp, int tip, Subsorter<E> tooTiny, Subsorter<E> notTooTiny)
    {
        super(cmp);
        this.TIP = tip;
        this.TOO_TINY = tooTiny;
        this.NOT_TOO_TINY = notTooTiny;
    }
    public final Subsorter<E> getSubsorter(int listSize)
    {
        return (listSize < this.TIP) ? this.TOO_TINY : this.NOT_TOO_TINY;
    }
    public final void introspectiveSort(List<E> list, int lower, int upper)
    {
        int pivot = super.pivotIn(list, lower, upper);
        if (pivot < 0) return;
        
        final int bottomSize = pivot - lower - 1;
        final int topSize = upper - pivot;
        int firstSize, secondSize, firstLower, firstUpper, secondLower, secondUpper;
        Subsorter<E> firstSubsorter, secondSubsorter;
        
        if (bottomSize < topSize)
        {
            firstSize = bottomSize;
            secondSize = topSize;
            firstLower = lower;
            firstUpper = pivot;
            secondLower = pivot + 1;
            secondUpper = upper;
        }
        else
        {
            firstSize = topSize;
            secondSize = bottomSize;
            firstLower = pivot + 1;
            firstUpper = upper;
            secondLower = lower;
            secondUpper = pivot;
        }
        firstSubsorter = getSubsorter(firstSize);
        secondSubsorter = getSubsorter(secondSize);

        firstSubsorter.sort(list, firstLower, firstUpper);
        secondSubsorter.sort(list, secondLower, secondUpper);
    }
    public final void pivotInSort(List<E> list, int lower, int upper)
    {
        int pivot = super.pivotIn(list, lower, upper);
        if (pivot < 0) return;
        pivotInSort(list, lower, pivot);
        pivotInSort(list, pivot + 1, upper);
    }
    public final void pivotDownUpSort(List<E> list, int lower, int upper)
    {
        int pivot = super.pivotDown(list, lower, upper);
        if (pivot < 0) return;
        pivotUpDownSort(list, lower, pivot);
        pivotUpDownSort(list, pivot + 1, upper);
    }
    public final void pivotUpDownSort(List<E> list, int lower, int upper)
    {
        int pivot = super.pivotUp(list, lower, upper);
        if (pivot < 0) return;
        pivotDownUpSort(list, lower, pivot);
        pivotDownUpSort(list, pivot + 1, upper);
    }
    public final void pivotDownSort(List<E> list, int lower, int upper)
    {
        int pivot = super.pivotDown(list, lower, upper);
        if (pivot < 0) return;
        pivotDownSort(list, lower, pivot);
        pivotDownSort(list, pivot + 1, upper);
    }
    public final void pivotUpSort(List<E> list, int lower, int upper)
    {
        int pivot = super.pivotUp(list, lower, upper);
        if (pivot < 0) return;
        pivotUpSort(list, lower, pivot);
        pivotUpSort(list, pivot + 1, upper);
    }
}

/** Go, Sorter. Go!
 *
 *  Is it pretty? Is it quick? Is it pretty quick?
 *
 *  Do you like thisPrettyQuickSorter?
 */
public class PrettyQuickSorters {
    
    private static final Multitool<String> tool = new Multitool<String>();

    private static final CountingSorter<String> thisPrettyQuickSorter =
        new Quicksorter<String>(String.CASE_INSENSITIVE_ORDER);

    private static final InjectableSorter<String> thatPrettyQuickSorter =
        (list, cmp) -> Collections.sort(list, cmp);

    private static final CountingComparator<String> comparator =
        new CountingComparator<String>(String.CASE_INSENSITIVE_ORDER);

    public static void main(String[] args)
    {        
        Long nanoSec1 = 0L, nanoSec2 = 0L;
        
        List<String> original = Arrays.asList(args);
        List<List<String>> permutations = tool.allPermutationsOf(original);

        for (List<String> permutation : permutations)
        {
            List<String> copy1 = tool.copy(permutation);
            tool.startTimer();
            thisPrettyQuickSorter.sort(copy1);
            nanoSec1 += tool.stopTimer();
            
            List<String> copy2 = tool.copy(permutation);
            tool.startTimer();
            thatPrettyQuickSorter.sort(copy2, comparator);
            nanoSec2 += tool.stopTimer();
        }

        System.out.println("Sorted " + permutations.size() + " permutations of " + original);

        System.out.println("This comparisons, exchanges, seconds: " +
            thisPrettyQuickSorter.comparisonCount() + ", " +
            thisPrettyQuickSorter.exchangeCount() + ", " +
            nanoSec1 / 1e9);

        System.out.println("That comparisons, exchanges, seconds: " +
            comparator.count() + ", ?, " + nanoSec2 / 1e9);
    }
}