mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
Replace Arrays.sort() with an efficient sort algorithm
This change reuses the existing insertion sort (which was previously what Arrays.sort() executed) in a full intro sort pipeline. The implementation is based on the Musser paper on intro sort (Musser, David R. "Introspective sorting and selection algorithms." Softw., Pract. Exper. 27.8 (1997): 983-993.) and Wikipedia's current description of the heap sort: http://en.wikipedia.org/wiki/Heapsort. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
parent
8b60a32f11
commit
605701e40a
@ -148,8 +148,100 @@ public class Arrays {
|
||||
});
|
||||
}
|
||||
|
||||
private final static int SORT_SIZE_THRESHOLD = 16;
|
||||
|
||||
public static <T> void sort(T[] array, Comparator<? super T> comparator) {
|
||||
// insertion sort
|
||||
introSort(array, comparator, 0, array.length, array.length);
|
||||
insertionSort(array, comparator);
|
||||
}
|
||||
|
||||
private static <T > void introSort(T[] array,
|
||||
Comparator<? super T> comparator, int begin, int end, int limit)
|
||||
{
|
||||
while (end - begin > SORT_SIZE_THRESHOLD) {
|
||||
if (limit == 0) {
|
||||
heapSort(array, comparator, begin, end);
|
||||
return;
|
||||
}
|
||||
limit >>= 1;
|
||||
|
||||
// median of three
|
||||
T a = array[begin];
|
||||
T b = array[begin + (end - begin) / 2 + 1];
|
||||
T c = array[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(array[i], median) < 0) {
|
||||
++i;
|
||||
}
|
||||
--j;
|
||||
while (comparator.compare(median, array[j]) < 0) {
|
||||
--j;
|
||||
}
|
||||
if (i >= j) {
|
||||
pivot = i;
|
||||
break;
|
||||
}
|
||||
T swap = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = swap;
|
||||
++i;
|
||||
}
|
||||
|
||||
introSort(array, comparator, pivot, end, limit);
|
||||
end = pivot;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void heapSort(T[] array, Comparator<? super T> comparator,
|
||||
int begin, int end)
|
||||
{
|
||||
int count = end - begin;
|
||||
for (int i = count / 2 - 1; i >= 0; --i) {
|
||||
siftDown(array, comparator, i, count, begin);
|
||||
}
|
||||
for (int i = count - 1; i > 0; --i) {
|
||||
// swap begin and begin + i
|
||||
T swap = array[begin + i];
|
||||
array[begin + i] = array[begin];
|
||||
array[begin] = swap;
|
||||
|
||||
siftDown(array, comparator, 0, i, begin);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void siftDown(T[] array, Comparator<? super T> comparator,
|
||||
int i, int count, int offset)
|
||||
{
|
||||
T value = array[offset + i];
|
||||
while (i < count / 2) {
|
||||
int child = 2 * i + 1;
|
||||
if (child + 1 < count &&
|
||||
comparator.compare(array[child], array[child + 1]) < 0) {
|
||||
++child;
|
||||
}
|
||||
if (comparator.compare(value, array[child]) >= 0) {
|
||||
break;
|
||||
}
|
||||
array[offset + i] = array[offset + child];
|
||||
i = child;
|
||||
}
|
||||
array[offset + i] = value;
|
||||
}
|
||||
|
||||
private static <T> void insertionSort(T[] array,
|
||||
Comparator<? super T> comparator)
|
||||
{
|
||||
for (int j = 1; j < array.length; ++j) {
|
||||
T t = array[j];
|
||||
int i = j - 1;
|
||||
|
@ -3,6 +3,41 @@ public class Arrays {
|
||||
if (! v) throw new RuntimeException();
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> void expectSorted(T[] array) {
|
||||
for (int i = 1; i < array.length; ++i) {
|
||||
expect(array[i - 1].compareTo(array[i]) <= 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static int pseudoRandom(int seed) {
|
||||
return 3170425 * seed + 132102;
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> int shuffle(T[] array, int seed) {
|
||||
for (int i = array.length; i > 1; --i) {
|
||||
int i2 = (seed < 0 ? -seed : seed) % i;
|
||||
T value = array[i - 1];
|
||||
array[i - 1] = array[i2];
|
||||
array[i2] = value;
|
||||
seed = pseudoRandom(seed);
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
public static void testSort() {
|
||||
Integer[] array = new Integer[64];
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = Integer.valueOf(i + 1);
|
||||
}
|
||||
;
|
||||
int random = 12345;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
random = shuffle(array, random);
|
||||
java.util.Arrays.sort(array);
|
||||
expectSorted(array);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
{ int[] array = new int[0];
|
||||
Exception exception = null;
|
||||
@ -94,5 +129,7 @@ public class Arrays {
|
||||
java.util.Arrays.hashCode(a);
|
||||
java.util.Arrays.hashCode((Object[])null);
|
||||
}
|
||||
|
||||
testSort();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user