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);
}
}