diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 91fad0964b..88df95a95f 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -33,6 +33,121 @@ public class Collections { shuffle(list, new Random()); } + public static void sort(List list) { + sort(list, new Comparator() { + public int compare(Object a, Object b) { + return ((Comparable) a).compareTo(b); + } + }); + } + + private final static int SORT_SIZE_THRESHOLD = 16; + + public static void sort(List list, Comparator comparator) { + int size = list.size(); + introSort(list, comparator, 0, size, size); + insertionSort(list, comparator); + } + + private static void introSort(List list, + Comparator comparator, int begin, int end, int limit) + { + while (end - begin > SORT_SIZE_THRESHOLD) { + if (limit == 0) { + heapSort(list, comparator, begin, end); + return; + } + limit >>= 1; + + // median of three + T a = list.get(begin); + T b = list.get(begin + (end - begin) / 2 + 1); + T c = list.get(end - 1); + T median; + if (comparator.compare(a, b) < 0) { + median = comparator.compare(b, c) < 0 ? + b : (comparator.compare(a, c) < 0 ? c : a); + } else { + median = comparator.compare(b, c) > 0 ? + b : (comparator.compare(a, c) > 0 ? c : a); + } + + // partition + int pivot, i = begin, j = end; + for (;;) { + while (comparator.compare(list.get(i), median) < 0) { + ++i; + } + --j; + while (comparator.compare(median, list.get(j)) < 0) { + --j; + } + if (i >= j) { + pivot = i; + break; + } + T swap = list.get(i); + list.set(i, list.get(j)); + list.set(j, swap); + ++i; + } + + introSort(list, comparator, pivot, end, limit); + end = pivot; + } + } + + private static void heapSort(List list, Comparator comparator, + int begin, int end) + { + int count = end - begin; + for (int i = count / 2 - 1; i >= 0; --i) { + siftDown(list, comparator, i, count, begin); + } + for (int i = count - 1; i > 0; --i) { + // swap begin and begin + i + T swap = list.get(begin + i); + list.set(begin + i, list.get(begin)); + list.set(begin, swap); + + siftDown(list, comparator, 0, i, begin); + } + } + + private static void siftDown(List list, Comparator comparator, + int i, int count, int offset) + { + T value = list.get(offset + i); + while (i < count / 2) { + int child = 2 * i + 1; + if (child + 1 < count && + comparator.compare(list.get(child), list.get(child + 1)) < 0) { + ++child; + } + if (comparator.compare(value, list.get(child)) >= 0) { + break; + } + list.set(offset + i, list.get(offset + child)); + i = child; + } + list.set(offset + i, value); + } + + private static void insertionSort(List list, + Comparator comparator) + { + int size = list.size(); + for (int j = 1; j < size; ++j) { + T t = list.get(j); + int i = j - 1; + while (i >= 0 && comparator.compare(list.get(i), t) > 0) { + list.set(i + 1, list.get(i)); + --i; + } + list.set(i + 1, t); + } + } + static T[] toArray(Collection collection, T[] array) { Class c = array.getClass().getComponentType(); diff --git a/test/Collections.java b/test/Collections.java index d175318a4f..d778267dde 100644 --- a/test/Collections.java +++ b/test/Collections.java @@ -1,9 +1,12 @@ +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; public class Collections { public static void main(String[] args) { testValues(); + testSort(); } @SuppressWarnings("rawtypes") @@ -23,4 +26,43 @@ public class Collections { // expected } } + + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static > void expectSorted(List list) { + for (int i = 1; i < list.size(); ++i) { + expect(list.get(i - 1).compareTo(list.get(i)) <= 0); + } + } + + private static int pseudoRandom(int seed) { + return 3170425 * seed + 132102; + } + + private static > int shuffle(List list, int seed) { + for (int i = list.size(); i > 1; --i) { + int i2 = (seed < 0 ? -seed : seed) % i; + T value = list.get(i - 1); + list.set(i - 1, list.get(i2)); + list.set(i2, value); + seed = pseudoRandom(seed); + } + return seed; + } + + public static void testSort() { + List list = new ArrayList(); + for (int i = 0; i < 64; ++i) { + list.add(Integer.valueOf(i + 1)); + } + ; + int random = 12345; + for (int i = 0; i < 32; ++i) { + random = shuffle(list, random); + java.util.Collections.sort(list); + expectSorted(list); + } + } }