diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..7e05835
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,20 @@
+name: Test sorts
+on: [push, pull_request]
+
+jobs:
+ test_java:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: "Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft"
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v2.1.0
+ with:
+ java-version: 8
+ distribution: zulu
+ - name: Build Tester
+ run: javac -d bin src/holygrail/*.java
+ - name: Run Tester
+ run: java -cp bin holygrail.Tester
diff --git a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project
index 4510e5a..eda8f51 100644
--- a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project
+++ b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project
@@ -14,4 +14,15 @@
org.eclipse.jdt.core.javanature
+
+
+ 1635186492658
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
diff --git a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java
index 8439eb6..3a84633 100644
--- a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java
+++ b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java
@@ -4,20 +4,20 @@
/*
* MIT License
- *
+ *
* Copyright (c) 2013 Andrey Astrelin
* Copyright (c) 2020-2021 The Holy Grail Sort Project
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -85,7 +85,7 @@ enum Subarray {
private int currBlockLen;
private Subarray currBlockOrigin;
-
+
public HolyGrailSort(Comparator cmp) {
this.cmp = cmp;
}
@@ -95,27 +95,27 @@ private static void swap(T[] array, int a, int b) {
array[a] = array[b];
array[b] = temp;
}
-
+
private static void swapBlocksForwards(T[] array, int a, int b, int blockLen) {
for(int i = 0; i < blockLen; i++) {
swap(array, a + i, b + i);
}
}
-
+
private static void swapBlocksBackwards(T[] array, int a, int b, int blockLen) {
for(int i = blockLen - 1; i >= 0; i--) {
swap(array, a + i, b + i);
}
}
-
+
// Shift elements [start + 1, start + length + 1) to the left by 1
// and paste copied element at start + length - 1.
private static void insertForwards(T[] array, int start, int length) {
T item = array[start];
System.arraycopy(array, start + 1, array, start, length);
- array[start + length] = item;
+ array[start + length] = item;
}
-
+
// Shift elements [start, start + length) to the right by 1
// and paste copied element at start.
private static void insertBackwards(T[] array, int start, int length) {
@@ -123,10 +123,10 @@ private static void insertBackwards(T[] array, int start, int length) {
System.arraycopy(array, start, array, start + 1, length);
array[start] = item;
}
-
+
private static void rotate(T[] array, int start, int leftLen, int rightLen) {
int minLen = leftLen <= rightLen ? leftLen : rightLen;
-
+
while(minLen > 1) {
if(leftLen <= rightLen) {
do {
@@ -134,7 +134,7 @@ private static void rotate(T[] array, int start, int leftLen, int rightLen)
start += leftLen;
rightLen -= leftLen;
} while(leftLen <= rightLen);
-
+
minLen = rightLen;
}
else {
@@ -142,7 +142,7 @@ private static void rotate(T[] array, int start, int leftLen, int rightLen)
swapBlocksBackwards(array, start + leftLen - rightLen, start + leftLen, rightLen);
leftLen -= rightLen;
} while(leftLen > rightLen);
-
+
minLen = leftLen;
}
}
@@ -156,18 +156,18 @@ private static void rotate(T[] array, int start, int leftLen, int rightLen)
}
}
}
-
+
// unguarded insertion sort
// implementation thanks to Control and Scandum!
private static void insertSort(T[] array, int start, int length, Comparator cmp) {
for(int item = 1; item < length; item++) {
T temp = array[start + item];
int index = start + item;
-
+
if(cmp.compare(array[index - 1], temp) <= 0) {
continue;
}
-
+
if(cmp.compare(array[start], temp) > 0) {
insertBackwards(array, start, item);
continue;
@@ -177,16 +177,16 @@ private static void insertSort(T[] array, int start, int length, Comparator<
array[index] = array[index - 1];
index--;
} while(cmp.compare(array[index - 1], temp) > 0);
-
+
array[index] = temp;
}
}
-
+
private static void shellPass(T[] array, int start, int length, int gap, Comparator cmp) {
for(int item = gap; item < length; item++) {
T temp = array[start + item];
int index = start + item;
-
+
if(cmp.compare(array[index - gap], temp) < 0) {
continue;
}
@@ -199,7 +199,7 @@ private static void shellPass(T[] array, int start, int length, int gap, Com
array[index] = temp;
}
}
-
+
// implementation of Shellsort using a modified version of
// Sedgewick's '82 gap sequence: 1, *3*, 8, 23, 77, 281, ...
// [4^k + 3*2^(k-1) + 1] with an added penultimate gap of 3
@@ -209,7 +209,7 @@ private static void shellSort(T[] array, int start, int length, Comparator 0) {
int gap = (4 << (2*k)) + (3 << k) + 1;
shellPass(array, start, length, gap, cmp);
@@ -218,7 +218,7 @@ private static void shellSort(T[] array, int start, int length, Comparator int binarySearchLeft(T[] array, int start, int length, T target, Comparator cmp) {
int left = 0;
@@ -227,7 +227,7 @@ private static int binarySearchLeft(T[] array, int start, int length, T targ
while(left < right) {
// equivalent to (left + right) / 2 with added overflow protection
int middle = (left + right) >>> 1;
-
+
if(cmp.compare(array[start + middle], target) < 0) {
left = middle + 1;
}
@@ -237,7 +237,7 @@ private static int binarySearchLeft(T[] array, int start, int length, T targ
}
return left;
}
-
+
// Technically a "upper bound" search
private static int binarySearchRight(T[] array, int start, int length, T target, Comparator cmp) {
int left = 0;
@@ -246,7 +246,7 @@ private static int binarySearchRight(T[] array, int start, int length, T tar
while(left < right) {
// equivalent to (left + right) / 2 with added overflow protection
int middle = (left + right) >>> 1;
-
+
if(cmp.compare(array[start + middle], target) > 0) {
right = middle;
}
@@ -256,7 +256,7 @@ private static int binarySearchRight(T[] array, int start, int length, T tar
}
return right;
}
-
+
// Returns -1 if an equal key is found, cutting off the search early
// FUTURE TODO: first & last key best-cases
private static int binarySearchExclusive(T[] array, int start, int length, T target, Comparator cmp) {
@@ -266,7 +266,7 @@ private static int binarySearchExclusive(T[] array, int start, int length, T
while(left < right) {
// equivalent to (left + right) / 2 with added overflow protection
int middle = (left + right) >>> 1;
-
+
int comp = cmp.compare(array[start + middle], target);
if(comp == 0) {
return -1;
@@ -280,7 +280,7 @@ else if(comp < 0) {
}
return left;
}
-
+
// cost: 2 * length + idealKeys^2 / 2
private static int collectKeys(T[] array, int start, int length, int idealKeys, Comparator cmp) {
int keysFound = 1; // by itself, the first item in the array is our first unique key
@@ -308,7 +308,7 @@ private static int collectKeys(T[] array, int start, int length, int idealKe
if(keysFound != insertPos) {
insertBackwards(array, start + firstKey + insertPos, keysFound - insertPos);
}
-
+
// One step closer to idealKeys.
keysFound++;
}
@@ -327,16 +327,16 @@ private static void sortPairsWithKeys(T[] array, int start, int length, Comp
// first, save the keys to stack memory
T firstKey = array[start - 1];
T secondKey = array[start - 2];
-
+
// move all the items down two indices, sorting them simultaneously
sortPairs(array, start, length, cmp);
-
+
// finally, stamp the saved keys (remember: order doesn't matter!)
// to the end of the array
array[start + length - 2] = firstKey;
array[start + length - 1] = secondKey;
}
-
+
private static void sortPairs(T[] array, int start, int length, Comparator cmp) {
int index;
for(index = 1; index < length; index += 2) {
@@ -358,9 +358,9 @@ private static void sortPairs(T[] array, int start, int length, Comparator "scrolling buffer"
- //
+ //
// "scrolling buffer" + array[start, middle - 1] + array[middle, end - 1]
// --> array[buffer, buffer + end - 1] + "scrolling buffer"
private static void mergeForwards(T[] array, int start, int leftLen, int rightLen,
@@ -416,7 +416,7 @@ private static void mergeBackwards(T[] array, int start, int leftLen, int ri
}
}
- // array[buffer .. start - 1] <=> "free space"
+ // array[buffer .. start - 1] <=> "free space"
//
// "free space" + array[start, middle - 1] + array[middle, end - 1]
// --> array[buffer, buffer + end - 1] + "free space"
@@ -445,9 +445,9 @@ private static void mergeForwardsOutOfPlace(T[] array, int start, int leftLe
if(buffer != left) {
System.arraycopy(array, left, array, buffer, middle - left);
-
+
// swapBlocksForwards(array, buffer, left, middle - left);
-
+
/*
while(left < middle) {
array[buffer] = array[left];
@@ -457,7 +457,7 @@ private static void mergeForwardsOutOfPlace(T[] array, int start, int leftLe
*/
}
}
-
+
private static void mergeBackwardsOutOfPlace(T[] array, int start, int leftLen, int rightLen,
int bufferOffset, Comparator cmp) {
int end = start - 1;
@@ -481,9 +481,9 @@ private static void mergeBackwardsOutOfPlace(T[] array, int start, int leftL
if(right != buffer) {
System.arraycopy(array, right, array, buffer, right - middle);
-
+
// swapBlocksBackwards(array, right, buffer, right - middle);
-
+
/*
while(right > middle) {
array[buffer] = array[right];
@@ -493,7 +493,7 @@ private static void mergeBackwardsOutOfPlace(T[] array, int start, int leftL
*/
}
}
-
+
private static void buildInPlace(T[] array, int start, int length, int currentLen, int bufferLen, Comparator cmp) {
for(int mergeLen = currentLen; mergeLen < bufferLen; mergeLen *= 2) {
int fullMerge = 2 * mergeLen;
@@ -518,7 +518,7 @@ private static void buildInPlace(T[] array, int start, int length, int curre
start -= mergeLen;
}
- int fullMerge = 2 * bufferLen;
+ int fullMerge = 2 * bufferLen;
int lastBlock = length % fullMerge;
int lastOffset = start + length - lastBlock;
@@ -533,7 +533,7 @@ private static void buildInPlace(T[] array, int start, int length, int curre
mergeBackwards(array, mergeIndex, bufferLen, bufferLen, bufferLen, cmp);
}
}
-
+
private void buildOutOfPlace(T[] array, int start, int length, int bufferLen, int extLen, Comparator cmp) {
System.arraycopy(array, start - extLen, this.extBuffer, 0, extLen);
@@ -565,7 +565,7 @@ private void buildOutOfPlace(T[] array, int start, int length, int bufferLen, in
}
if(extLen == bufferLen) {
- int fullMerge = 2 * bufferLen;
+ int fullMerge = 2 * bufferLen;
int lastBlock = length % fullMerge;
int lastOffset = start + length - lastBlock;
@@ -585,7 +585,7 @@ private void buildOutOfPlace(T[] array, int start, int length, int bufferLen, in
buildInPlace(array, start, length, mergeLen, bufferLen, cmp);
}
}
-
+
// build blocks of length 'bufferLen'
// input: [start - mergeLen, start - 1] elements are buffer
// output: first 'bufferLen' elements are buffer, blocks (2 * bufferLen) and last subblock sorted
@@ -611,7 +611,7 @@ private void buildBlocks(T[] array, int start, int length, int bufferLen, Compar
buildInPlace(array, start - 2, length, 2, bufferLen, cmp);
}
}
-
+
// implementation of "smart block selection" sort
// code inspired by Anonymous0726
private static void sortBlocks(T[] array, int firstKey, int start, int blockCount,
@@ -619,17 +619,17 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block
boolean sortByTail, Comparator cmp) {
// this check might be unnecessary with the new "combine blocks" control flow
if(blockCount == leftBlocks) return;
-
+
int cmpIndex = sortByTail ? blockLen - 1 : 0;
-
+
int blockIndex = start;
int keyIndex = firstKey;
-
+
int rightBlock = start + (leftBlocks * blockLen);
int rightKey = firstKey + leftBlocks;
-
+
boolean sorted = true;
-
+
// phase one: find first index in left subarray where a smaller right block can be swapped;
// if no swaps occur, the subarrays are already in order
do {
@@ -643,9 +643,9 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block
} while(sorted && keyIndex < rightKey);
if(sorted) return;
-
+
// consider anonymous' suggestion
-
+
int lastKey = firstKey + blockCount - 1;
int scrambledEnd = rightKey < lastKey ? rightKey + 1 : rightKey;
@@ -674,7 +674,7 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block
blockIndex += blockLen;
keyIndex++;
}
-
+
// phase three: after the left subarray has been sorted, keep finding the next block in order
// from the scrambled area until either (a) the scrambled area runs out of blocks,
// meaning the rest are sorted, or (b) the scrambled area hits the end of the right
@@ -703,17 +703,17 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block
blockIndex += blockLen;
keyIndex++;
-
+
if(keyIndex == scrambledEnd) return;
}
-
+
// phase four: sort the remainder blocks from the scrambled area
do {
int selectBlock = blockIndex;
int selectKey = keyIndex;
-
+
int currBlock = blockIndex + blockLen;
-
+
for(int currKey = keyIndex + 1; currKey <= lastKey; currKey++, currBlock += blockLen) {
int compare = cmp.compare(array[currBlock + cmpIndex], array[selectBlock + cmpIndex]);
if (compare < 0 || (compare == 0 && cmp.compare(array[ currKey],
@@ -722,32 +722,32 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block
selectKey = currKey;
}
}
-
+
if(selectKey != keyIndex) {
swapBlocksForwards(array, blockIndex, selectBlock, blockLen);
swap(array, keyIndex, selectKey);
}
-
+
blockIndex += blockLen;
keyIndex++;
} while(keyIndex < lastKey);
-
+
/*
for(int blockIndex = 0, keyIndex = 0; keyIndex < keyCount; blockIndex += blockLen, keyIndex++) {
int selectBlock = blockIndex;
int selectKey = keyIndex;
-
+
for(int currBlock = selectBlock + blockLen, currKey = keyIndex + 1;
currKey < keyCount; currBlock += blockLen, currKey++) {
-
- int compare = cmp.compare(array[start + currBlock], array[start + selectBlock]);
+
+ int compare = cmp.compare(array[start + currBlock], array[start + selectBlock]);
if (compare < 0 || (compare == 0 && cmp.compare(array[firstKey + currKey],
array[firstKey + selectKey]) < 0)) {
selectBlock = currBlock;
selectKey = currKey;
}
}
-
+
if(selectKey != keyIndex) {
swapBlocksForwards(array, start + blockIndex, start + selectBlock, blockLen);
swap(array, firstKey + keyIndex, firstKey + selectKey);
@@ -755,7 +755,7 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block
}
*/
}
-
+
/*
private static void rewindBuffer(T[] array, int start, int leftBlock, int buffer) {
while(leftBlock >= start) {
@@ -772,7 +772,7 @@ private static void rewindOutOfPlace(T[] array, int start, int leftBlock, in
buffer--;
}
}
-
+
private static void fastForwardBuffer(T[] array, int buffer, int rightBlock, int end) {
while(rightBlock <= end) {
swap(array, rightBlock, buffer);
@@ -780,7 +780,7 @@ private static void fastForwardBuffer(T[] array, int buffer, int rightBlock,
buffer++;
}
}
-
+
private static void fastForwardOutOfPlace(T[] array, int buffer, int rightBlock, int end) {
while(rightBlock <= end) {
array[buffer] = array[rightBlock];
@@ -788,13 +788,13 @@ private static void fastForwardOutOfPlace(T[] array, int buffer, int rightBl
buffer++;
}
}
-
+
// Swaps Grailsort's "scrolling buffer" from the right side of the array all the way back to 'start'.
// Costs O(n) swaps.
private static void resetBuffer(T[] array, int start, int length, int bufferOffset) {
int buffer = start + length - 1;
int index = buffer - bufferOffset;
-
+
while(buffer >= start) {
swap(array, index, buffer);
buffer--;
@@ -802,7 +802,7 @@ private static void resetBuffer(T[] array, int start, int length, int buffer
}
}
*/
-
+
private static Subarray getSubarray(T[] array, int currentKey, T medianKey, Comparator cmp) {
if(cmp.compare(array[currentKey], medianKey) < 0) {
return Subarray.LEFT;
@@ -811,7 +811,7 @@ private static Subarray getSubarray(T[] array, int currentKey, T medianKey,
return Subarray.RIGHT;
}
}
-
+
// FUNCTION RE-RENAMED: last/final left blocks are used to calculate the length of the final merge
private static int countLastMergeBlocks(T[] array, int offset, int blockCount, int blockLen,
Comparator cmp) {
@@ -828,7 +828,7 @@ private static int countLastMergeBlocks(T[] array, int offset, int blockCoun
return blocksToMerge;
}
-
+
private void localMergeForwards(T[] array, int start, int leftLen, Subarray leftOrigin, int rightLen,
int bufferOffset, Comparator cmp) {
int buffer = start - bufferOffset;
@@ -861,14 +861,14 @@ private void localMergeForwards(T[] array, int start, int leftLen, Subarray left
right++;
}
buffer++;
- }
+ }
}
if(left < middle) {
int leftFrag = middle - left;
swapBlocksBackwards(array, left, end - leftFrag, leftFrag);
this.currBlockLen = leftFrag;
-
+
//this.currBlockLen = leftFrag;
//rewindBuffer(array, left, middle - 1, end - 1);
}
@@ -890,7 +890,7 @@ private void localMergeBackwards(T[] array, int start, int leftLen, int rightLen
int middle = left;
int right = middle + rightLen;
int buffer = right + bufferOffset;
-
+
if(rightOrigin == Subarray.RIGHT) {
while(left > end && right > middle) {
if(cmp.compare(array[left], array[right]) > 0) {
@@ -917,12 +917,12 @@ private void localMergeBackwards(T[] array, int start, int leftLen, int rightLen
buffer--;
}
}
-
+
if(right > middle) {
int rightFrag = right - middle;
swapBlocksForwards(array, end + 1, middle + 1, rightFrag);
this.currBlockLen = rightFrag;
-
+
//this.currBlockLen = right - middle;
//fastForwardBuffer(array, end + 1, middle + 1, right);
}
@@ -936,11 +936,11 @@ private void localMergeBackwards(T[] array, int start, int leftLen, int rightLen
}
}
}
-
+
private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrigin, int rightLen,
Comparator cmp) {
int middle = start + leftLen;
-
+
if(leftOrigin == Subarray.LEFT) {
if(cmp.compare(array[middle - 1], array[middle]) > 0) {
while(leftLen != 0) {
@@ -948,12 +948,12 @@ private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrig
if(mergeLen != 0) {
rotate(array, start, leftLen, mergeLen);
-
+
start += mergeLen;
middle += mergeLen;
rightLen -= mergeLen;
}
-
+
if(rightLen == 0) {
this.currBlockLen = leftLen;
return;
@@ -975,12 +975,12 @@ private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrig
if(mergeLen != 0) {
rotate(array, start, leftLen, mergeLen);
-
+
start += mergeLen;
middle += mergeLen;
rightLen -= mergeLen;
}
-
+
if(rightLen == 0) {
this.currBlockLen = leftLen;
return;
@@ -1004,7 +1004,7 @@ private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrig
this.currBlockOrigin = Subarray.LEFT;
}
}
-
+
// FUNCTION RENAMED: more consistent with other "out-of-place" merges
private void localMergeForwardsOutOfPlace(T[] array, int start, int leftLen, Subarray leftOrigin,
int rightLen, int bufferOffset,
@@ -1039,18 +1039,18 @@ private void localMergeForwardsOutOfPlace(T[] array, int start, int leftLen, Sub
right++;
}
buffer++;
- }
+ }
}
if(left < middle) {
int leftFrag = middle - left;
System.arraycopy(array, left, array, end - leftFrag, leftFrag);
this.currBlockLen = leftFrag;
-
+
//int leftFrag = middle - left;
//swapBlocksBackwards(array, left, end - leftFrag, leftFrag);
//this.currBlockLen = leftFrag;
-
+
//this.currBlockLen = middle - left;
//rewindOutOfPlace(array, left, middle - 1, end - 1);
}
@@ -1064,7 +1064,7 @@ private void localMergeForwardsOutOfPlace(T[] array, int start, int leftLen, Sub
}
}
}
-
+
private void localMergeBackwardsOutOfPlace(T[] array, int start, int leftLen, int rightLen, Subarray rightOrigin,
int bufferOffset, Comparator cmp) {
int end = start - 1;
@@ -1104,11 +1104,11 @@ private void localMergeBackwardsOutOfPlace(T[] array, int start, int leftLen, in
int rightFrag = right - middle;
System.arraycopy(array, middle + 1, array, end + 1, rightFrag);
this.currBlockLen = rightFrag;
-
+
//int rightFrag = right - middle;
//swapBlocksForwards(array, end + 1, middle + 1, rightFrag);
//this.currBlockLen = rightFrag;
-
+
//this.currBlockLen = right - middle;
//fastForwardOutOfPlace(array, end + 1, middle + 1, right);
}
@@ -1142,7 +1142,7 @@ private void mergeBlocksForwards(T[] array, int firstKey, T medianKey, int start
if(nextBlockOrigin != this.currBlockOrigin) {
this.localMergeForwards(array, currBlock, this.currBlockLen, this.currBlockOrigin,
- blockLen, blockLen, cmp);
+ blockLen, blockLen, cmp);
}
else {
buffer = currBlock - blockLen;
@@ -1216,18 +1216,18 @@ private void lazyMergeBlocks(T[] array, int firstKey, T medianKey, int start,
private void mergeBlocksBackwards(T[] array, int firstKey, T medianKey, int start,
int blockCount, int blockLen, int lastLen, Comparator cmp) {
-
+
int nextBlock = start + (blockCount * blockLen) - 1;
int buffer = nextBlock + lastLen + blockLen;
-
+
// The last fragment (lastLen) came from the right subarray,
// although it may be empty (lastLen == 0)
this.currBlockLen = lastLen;
this.currBlockOrigin = Subarray.RIGHT;
-
+
for(int keyIndex = blockCount - 1; keyIndex >= 0; keyIndex--, nextBlock -= blockLen) {
Subarray nextBlockOrigin = getSubarray(array, firstKey + keyIndex, medianKey, cmp);
-
+
if(nextBlockOrigin != this.currBlockOrigin) {
// TODO: buffer length *should* always be equivalent to:
// right block length - forwards merge blocks
@@ -1242,10 +1242,10 @@ private void mergeBlocksBackwards(T[] array, int firstKey, T medianKey, int star
this.currBlockLen = blockLen;
}
}
-
+
swapBlocksBackwards(array, start, start + blockLen, this.currBlockLen);
}
-
+
private void mergeBlocksForwardsOutOfPlace(T[] array, int firstKey, T medianKey, int start,
int blockCount, int blockLen, int lastMergeBlocks,
int lastLen, Comparator cmp) {
@@ -1260,12 +1260,12 @@ private void mergeBlocksForwardsOutOfPlace(T[] array, int firstKey, T medianKey,
for(int keyIndex = 1; keyIndex < blockCount; keyIndex++, nextBlock += blockLen) {
Subarray nextBlockOrigin;
- currBlock = nextBlock - this.currBlockLen;
+ currBlock = nextBlock - this.currBlockLen;
nextBlockOrigin = getSubarray(array, firstKey + keyIndex, medianKey, cmp);
if(nextBlockOrigin != this.currBlockOrigin) {
this.localMergeForwardsOutOfPlace(array, currBlock, this.currBlockLen, this.currBlockOrigin,
- blockLen, blockLen, cmp);
+ blockLen, blockLen, cmp);
}
else {
buffer = currBlock - blockLen;
@@ -1297,20 +1297,20 @@ private void mergeBlocksForwardsOutOfPlace(T[] array, int firstKey, T medianKey,
System.arraycopy(array, currBlock, array, buffer, this.currBlockLen);
}
}
-
+
private void mergeBlocksBackwardsOutOfPlace(T[] array, int firstKey, T medianKey, int start,
int blockCount, int blockLen, int lastLen, Comparator cmp) {
int nextBlock = start + (blockCount * blockLen) - 1;
int buffer = nextBlock + lastLen + blockLen;
-
+
// The last fragment (lastLen) came from the right subarray,
// although it may be empty (lastLen == 0)
this.currBlockLen = lastLen;
this.currBlockOrigin = Subarray.RIGHT;
-
+
for(int keyIndex = blockCount - 1; keyIndex >= 0; keyIndex--, nextBlock -= blockLen) {
Subarray nextBlockOrigin = getSubarray(array, firstKey + keyIndex, medianKey, cmp);
-
+
if(nextBlockOrigin != this.currBlockOrigin) {
this.localMergeBackwardsOutOfPlace(array, nextBlock - blockLen + 1, blockLen, this.currBlockLen, this.currBlockOrigin,
blockLen, cmp);
@@ -1321,10 +1321,10 @@ private void mergeBlocksBackwardsOutOfPlace(T[] array, int firstKey, T medianKey
this.currBlockLen = blockLen;
}
}
-
+
System.arraycopy(array, start, array, start + blockLen, this.currBlockLen);
}
-
+
// a novel, elegant, and incredibly efficient 1.5 sqrt n key sort, courtesy of Control
// only works if a) median key is known and b) keys were permutated by "sortBlocks"
// (keys < medianKey and >= medianKey are each in relative sorted order, resembling a final radix sort pass)
@@ -1332,7 +1332,7 @@ private static void sortKeys(T[] array, int firstKey, T medianKey, int keyCo
int currKey = firstKey;
int keysEnd = firstKey + keyCount;
int bufferSwaps = 0;
-
+
while(currKey < keysEnd) {
if(cmp.compare(array[currKey], medianKey) < 0) {
if(bufferSwaps != 0) {
@@ -1345,13 +1345,13 @@ private static void sortKeys(T[] array, int firstKey, T medianKey, int keyCo
}
currKey++;
}
-
+
swapBlocksBackwards(array, currKey - bufferSwaps, buffer, bufferSwaps);
}
-
+
private static void groupKeys(T[] array, int left, int right, T medianKey, Comparator cmp) {
while(left < right && cmp.compare(array[left], medianKey) < 0) left++;
-
+
for(int i = left + 1; i < right; i++) {
if(cmp.compare(array[i], medianKey) < 0) {
insertBackwards(array, left, i - left);
@@ -1363,10 +1363,10 @@ private static void groupKeys(T[] array, int left, int right, T medianKey, C
private static void mergeGroups(T[] array, int left, int middle, int right, T medianKey, Comparator cmp) {
int leftLen = middle - left;
int rightLen = right - middle;
-
+
int mergeStart = left + binarySearchLeft(array, left, leftLen, medianKey, cmp);
int mergeLen = binarySearchLeft(array, middle, rightLen, medianKey, cmp);
-
+
rotate(array, mergeStart, middle - mergeStart, mergeLen);
}
@@ -1377,41 +1377,41 @@ private static void mergeGroups(T[] array, int left, int middle, int right,
private static void lazySortKeys(T[] array, int firstKey, int keyCount, T medianKey, Comparator cmp) {
int runLen = 8;
int keysEnd = firstKey + keyCount;
-
+
int i;
for(i = firstKey; i + runLen < keysEnd; i += runLen) {
groupKeys(array, i, i + runLen, medianKey, cmp);
}
groupKeys(array, i, keysEnd, medianKey, cmp);
-
+
while(runLen < keyCount) {
int fullMerge = 2 * runLen;
-
+
int mergeIndex;
int mergeEnd = keysEnd - fullMerge;
-
+
for(mergeIndex = firstKey; mergeIndex <= mergeEnd; mergeIndex += fullMerge) {
mergeGroups(array, mergeIndex, mergeIndex + runLen, mergeIndex + fullMerge, medianKey, cmp);
}
-
+
int leftOver = keysEnd - mergeIndex;
if(leftOver > runLen) {
mergeGroups(array, mergeIndex, mergeIndex + runLen, keysEnd, medianKey, cmp);
}
-
+
runLen *= 2;
}
}
-
+
private void combineForwards(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) {
Comparator cmp = this.cmp; // local variable for performance à la Timsort
// TODO: Double-check names and change all other functions to match
int mergeLen = 2 * subarrayLen;
- int fullMerges = length / mergeLen;
+ int fullMerges = length / mergeLen;
int blockCount = mergeLen / blockLen;
int lastSubarrays = length - (mergeLen * fullMerges);
-
+
int fastForwardLen = 0;
if(lastSubarrays <= subarrayLen) {
if(fullMerges % 2 != 0) {
@@ -1420,26 +1420,26 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int
length -= lastSubarrays;
lastSubarrays = 0;
}
-
+
int leftBlocks = subarrayLen / blockLen;
T medianKey = array[firstKey + leftBlocks];
-
+
for(int mergeIndex = 0; mergeIndex < fullMerges; mergeIndex++) {
int offset = start + (mergeIndex * mergeLen);
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp);
this.mergeBlocksForwards(array, firstKey, medianKey, offset, blockCount, blockLen, 0, 0, cmp);
-
+
// TODO: Replace with Control's key sort
sortKeys(array, firstKey, medianKey, blockCount, offset + mergeLen - blockLen, cmp);
//insertSort(array, firstKey, blockCount, cmp);
}
int offset = start + (fullMerges * mergeLen);
-
+
if(lastSubarrays != 0) {
blockCount = lastSubarrays / blockLen;
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp);
int lastFragment = lastSubarrays - (blockCount * blockLen);
@@ -1462,10 +1462,10 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int
//TODO: Why is this 'blockCount + 1'???
sortKeys(array, firstKey, medianKey, blockCount, offset + lastSubarrays - blockLen, cmp);
//insertSort(array, firstKey, blockCount, cmp);
-
+
if(fullMerges % 2 == 0 && fullMerges != 0) {
swapBlocksBackwards(array, offset - blockLen, offset, lastSubarrays);
-
+
// lastSubarrays--;
// rewindBuffer(array, offset - blockLen, offset + lastSubarrays - blockLen, offset + lastSubarrays);
}
@@ -1475,7 +1475,7 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int
if(fullMerges % 2 != 0 && fullMerges != 1) {
// TODO: Double-check if this is equivalent to the rewindBuffer version...
swapBlocksBackwards(array, offset - blockLen - mergeLen, offset - blockLen, mergeLen);
-
+
// TODO: check arguments
// rewindBuffer(array, offset - mergeLen - blockLen, offset - blockLen - 1, offset - 1);
}
@@ -1485,21 +1485,21 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int
// fastForwardBuffer(array, offset - blockLen, offset, offset + fastForwardLen - 1);
}
}
-
+
/*
// ceil division of length over subarrayLen mod 4
int mergeCount = ((length - 1) / subarrayLen) + 1;
int bufferControl = mergeCount % 4;
-
+
if(bufferControl == 1) {
-
+
}
else if(bufferControl == 2) {
-
+
}
*/
}
-
+
private void lazyCombine(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) {
Comparator cmp = this.cmp; // local variable for performance à la Timsort
@@ -1507,27 +1507,27 @@ private void lazyCombine(T[] array, int firstKey, int start, int length, int sub
int fullMerges = length / mergeLen;
int blockCount = mergeLen / blockLen;
int lastSubarrays = length - (mergeLen * fullMerges);
-
+
if(lastSubarrays <= subarrayLen) {
length -= lastSubarrays;
lastSubarrays = 0;
}
-
+
int leftBlocks = subarrayLen / blockLen;
T medianKey = array[firstKey + leftBlocks];
-
+
for(int mergeIndex = 0; mergeIndex < fullMerges; mergeIndex++) {
int offset = start + (mergeIndex * mergeLen);
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp);
this.lazyMergeBlocks(array, firstKey, medianKey, offset, blockCount, blockLen, 0, 0, cmp);
-
+
lazySortKeys(array, firstKey, blockCount, medianKey, cmp);
//insertSort(array, firstKey, blockCount, cmp);
}
int offset = start + (fullMerges * mergeLen);
-
+
if(lastSubarrays != 0) {
blockCount = lastSubarrays / blockLen;
@@ -1555,26 +1555,26 @@ private void lazyCombine(T[] array, int firstKey, int start, int length, int sub
lazySortKeys(array, firstKey, blockCount, medianKey, cmp);
}
}
-
+
private void combineBackwards(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) {
Comparator cmp = this.cmp; // local variable for performance à la Timsort
int mergeLen = 2 * subarrayLen;
int fullMerges = length / mergeLen;
int lastSubarrays = length - (mergeLen * fullMerges);
-
+
if(lastSubarrays <= subarrayLen) {
length -= lastSubarrays;
lastSubarrays = 0;
}
-
+
int blockCount = lastSubarrays / blockLen;
int leftBlocks = subarrayLen / blockLen;
T medianKey = array[firstKey + leftBlocks];
-
+
if(lastSubarrays != 0) {
int offset = start + (fullMerges * mergeLen);
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, true, cmp);
int lastFragment = lastSubarrays - (blockCount * blockLen);
@@ -1588,20 +1588,20 @@ private void combineBackwards(T[] array, int firstKey, int start, int length, in
sortKeys(array, firstKey, medianKey, blockCount, offset, cmp);
//insertSort(array, firstKey, blockCount, cmp);
}
-
+
blockCount = mergeLen / blockLen;
-
+
for(int mergeIndex = fullMerges - 1; mergeIndex >= 0; mergeIndex--) {
int offset = start + (mergeIndex * mergeLen);
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, true, cmp);
this.mergeBlocksBackwards(array, firstKey, medianKey, offset, blockCount, blockLen, 0, cmp);
-
+
sortKeys(array, firstKey, medianKey, blockCount, offset, cmp);
//insertSort(array, firstKey, blockCount, cmp);
}
}
-
+
private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) {
Comparator cmp = this.cmp; // local variable for performance à la Timsort
@@ -1609,7 +1609,7 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l
int fullMerges = length / mergeLen;
int blockCount = mergeLen / blockLen;
int lastSubarrays = length - (mergeLen * fullMerges);
-
+
int fastForwardLen = 0;
if(lastSubarrays <= subarrayLen) {
if(fullMerges % 2 != 0) {
@@ -1618,21 +1618,21 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l
length -= lastSubarrays;
lastSubarrays = 0;
}
-
+
int leftBlocks = subarrayLen / blockLen;
T medianKey = array[firstKey + leftBlocks];
-
+
for(int mergeIndex = 0; mergeIndex < fullMerges; mergeIndex++) {
int offset = start + (mergeIndex * mergeLen);
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp);
this.mergeBlocksForwardsOutOfPlace(array, firstKey, medianKey, offset, blockCount, blockLen, 0, 0, cmp);
-
+
insertSort(array, firstKey, blockCount, cmp);
}
int offset = start + (fullMerges * mergeLen);
-
+
if(lastSubarrays != 0) {
blockCount = lastSubarrays / blockLen;
@@ -1657,12 +1657,12 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l
//TODO: Why is this 'blockCount + 1'???
insertSort(array, firstKey, blockCount, cmp);
-
+
if(fullMerges % 2 == 0 && fullMerges != 0) {
System.arraycopy(array, offset - blockLen, array, offset, lastSubarrays);
-
+
// swapBlocksBackwards(array, offset - blockLen, offset, lastSubarrays);
-
+
// lastSubarrays--;
// rewindOutOfPlace(array, offset - blockLen, offset + lastSubarrays - blockLen, offset + lastSubarrays);
}
@@ -1672,42 +1672,42 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l
if(fullMerges % 2 != 0 && fullMerges != 1) {
// TODO: Double-check if this is equivalent to the rewindBuffer version...
System.arraycopy(array, offset - blockLen - mergeLen, array, offset - blockLen, mergeLen);
-
+
// swapBlocksBackwards(array, offset - blockLen - mergeLen, offset - blockLen, mergeLen);
-
+
// TODO: check arguments
// rewindOutOfPlace(array, offset - fullMerge - blockLen, offset - blockLen - 1, offset - 1);
}
}
else {
System.arraycopy(array, offset, array, offset - blockLen, fastForwardLen);
-
+
// swapBlocksForwards(array, offset - blockLen, offset, fastForwardLen);
-
+
// fastForwardOutOfPlace(array, offset - blockLen, offset, offset + fastForwardLen - 1);
}
}
}
-
+
private void combineBackwardsOutOfPlace(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) {
Comparator cmp = this.cmp; // local variable for performance à la Timsort
int mergeLen = 2 * subarrayLen;
int fullMerges = length / mergeLen;
int lastSubarrays = length - (mergeLen * fullMerges);
-
+
if(lastSubarrays <= subarrayLen) {
length -= lastSubarrays;
lastSubarrays = 0;
}
-
+
int blockCount = lastSubarrays / blockLen;
int leftBlocks = subarrayLen / blockLen;
T medianKey = array[firstKey + leftBlocks];
-
+
if(lastSubarrays != 0) {
int offset = start + (fullMerges * mergeLen);
-
+
if(lastSubarrays - subarrayLen <= blockLen) {
mergeBackwards(array, offset, subarrayLen, lastSubarrays - subarrayLen, blockLen, cmp);
}
@@ -1725,28 +1725,28 @@ private void combineBackwardsOutOfPlace(T[] array, int firstKey, int start, int
insertSort(array, firstKey, blockCount, cmp);
}
}
-
+
blockCount = mergeLen / blockLen;
-
+
for(int mergeIndex = fullMerges - 1; mergeIndex >= 0; mergeIndex--) {
int offset = start + (mergeIndex * mergeLen);
-
+
sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, true, cmp);
this.mergeBlocksBackwardsOutOfPlace(array, firstKey, medianKey, offset, blockCount, blockLen, 0, cmp);
-
+
insertSort(array, firstKey, blockCount, cmp);
}
}
-
+
// 'keys' are on the left side of array. Blocks of length 'subarrayLen' combined. We'll combine them in pairs
// 'subarrayLen' is a power of 2. (2 * subarrayLen / blockLen) keys are guaranteed
private LocalMerge combineBlocks(T[] array, int start, int length, int bufferLen, int subarrayLen,
int blockLen, int keyLen, boolean idealBuffer) {
LocalMerge direction = LocalMerge.FORWARDS;
subarrayLen *= 2;
-
+
T[] extBuffer = this.extBuffer;
-
+
if(idealBuffer) {
if(extBuffer == null) {
while((length - bufferLen) > subarrayLen) {
@@ -1782,7 +1782,7 @@ private LocalMerge combineBlocks(T[] array, int start, int length, int bufferLen
else {
int keyBuffer = keyLen / 2;
shellSort(array, start, keyBuffer, this.cmp);
-
+
if(extBuffer == null) {
while(keyBuffer >= ((2 * subarrayLen) / keyBuffer)) {
if(direction == LocalMerge.FORWARDS) {
@@ -1821,17 +1821,17 @@ private LocalMerge combineBlocks(T[] array, int start, int length, int bufferLen
}
shellSort(array, start, keyLen, this.cmp);
-
+
while((length - keyLen) > subarrayLen) {
this.lazyCombine(array, start, start + keyLen, length - keyLen,
subarrayLen, (2 * subarrayLen) / keyLen);
subarrayLen *= 2;
}
}
-
+
return direction;
}
-
+
// "Classic" in-place merge sort using binary searches and rotations
// Forwards rotates the leftLen into the rightLen
// cost: leftLen^2 + rightLen
@@ -1861,14 +1861,14 @@ private static void lazyMergeForwards(T[] array, int start, int leftLen, int
}
}
}
-
+
// "Classic" in-place merge sort using binary searches and rotations
// Backwards rotates the rigthLen into the leftLen
// cost: rightLen^2 + leftLen
private static void lazyMergeBackwards(T[] array, int start, int leftLen, int rightLen, Comparator cmp) {
int end = start + leftLen + rightLen - 1;
- while(rightLen != 0) {
+ while(rightLen != 0) {
int mergeLen = binarySearchRight(array, start, leftLen, array[end], cmp);
if(mergeLen != leftLen) {
@@ -1892,11 +1892,11 @@ private static void lazyMergeBackwards(T[] array, int start, int leftLen, in
}
}
}
-
+
private static void lazyMergeBufferBackwards(T[] array, int start, int leftLen, int rightLen, Comparator cmp) {
int end = start + leftLen + rightLen - 1;
- while(rightLen != 0) {
+ while(rightLen != 0) {
int mergeLen = binarySearchLeft(array, start, leftLen, array[end], cmp);
if(mergeLen != leftLen) {
@@ -1920,7 +1920,7 @@ private static void lazyMergeBufferBackwards(T[] array, int start, int leftL
}
}
}
-
+
private static void lazyStableSort(T[] array, int start, int length, Comparator cmp) {
int i;
for(i = 0; i <= length - 16; i += 16) {
@@ -1944,48 +1944,48 @@ private static void lazyStableSort(T[] array, int start, int length, Compara
}
}
}
-
+
void commonSort(T[] array, int start, int length, T[] extBuffer, int extBufferLen) {
if(length < 16) {
insertSort(array, start, length, this.cmp);
return;
}
-
+
// smallest possible O(sqrt n) block length that
// doesn't include arrays sorted by Insertion Sort
int blockLen = 4;
-
+
// find the smallest power of two greater than or
// equal to the square root of the input's length
while((blockLen * blockLen) < length) {
blockLen *= 2;
}
-
+
// '((a - 1) / b) + 1' is actually a clever and very efficient
// formula for the ceiling of (a / b)
//
// credit to Anonymous0726 for figuring this out!
-
+
// TODO: We don't need this ceiling???
int keyLen = ((length - 1) / blockLen) + 1;
-
+
// Holy Grail is hoping to find '~2 sqrt n' unique items
// throughout the array
int idealKeys = keyLen + blockLen;
-
+
int keysFound = collectKeys(array, start, length, idealKeys, this.cmp);
-
+
boolean idealBuffer;
if(keysFound < idealKeys) {
-
+
// HOLY GRAIL STRATEGY 3
// No block swaps or scrolling buffer; resort to Lazy Stable Sort
if(keysFound < 4) {
-
+
// if all items in the array equal each other,
// then they're already sorted. done!
if(keysFound == 1) return;
-
+
lazyStableSort(array, start, length, this.cmp);
return;
}
@@ -2006,7 +2006,7 @@ void commonSort(T[] array, int start, int length, T[] extBuffer, int extBufferLe
// Block swaps with scrolling buffer
idealBuffer = true;
}
-
+
int bufferLen = blockLen + keyLen;
int subarrayLen;
if(idealBuffer) {
@@ -2015,22 +2015,22 @@ void commonSort(T[] array, int start, int length, T[] extBuffer, int extBufferLe
else {
subarrayLen = keyLen;
}
-
+
if(extBuffer != null) {
// GRAILSORT + EXTRA SPACE
this.extBuffer = extBuffer;
this.extBufferLen = extBufferLen;
}
-
+
this.buildBlocks(array, start + bufferLen, length - bufferLen, subarrayLen, this.cmp);
-
+
// TODO: Handle case where external buffer is not large enough for combine blocks
-
+
LocalMerge direction = this.combineBlocks(array, start, length, bufferLen, subarrayLen,
blockLen, keyLen, idealBuffer);
-
+
// TODO: Paste external buffer back into array
-
+
// This 'if' case will always run during Strategy 2
if(direction == LocalMerge.FORWARDS) {
shellSort(array, start + keyLen, blockLen, this.cmp);
diff --git a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java
index 26cfb39..cbb45ce 100644
--- a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java
+++ b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java
@@ -1,46 +1,263 @@
package holygrail;
+import java.lang.reflect.Array;
+import java.util.Arrays;
import java.util.Comparator;
-interface IntegerPair {
- public Integer getKey();
- public Integer getValue();
-}
+public class Tester {
+ static class SortFailedException extends Exception {
+ }
-class GrailPair implements IntegerPair {
- private Integer key;
- private Integer value;
-
- public GrailPair(Integer key, Integer value) {
- this.key = key;
- this.value = value;
+ static interface IntegerPair {
+ public Integer getKey();
+ public Integer getValue();
}
- @Override
- public Integer getKey() {
- return this.key;
+
+ static class GrailPair implements IntegerPair {
+ private Integer key;
+ private Integer value;
+
+ public GrailPair(Integer key, Integer value) {
+ this.key = key;
+ this.value = value;
+ }
+ @Override
+ public Integer getKey() {
+ return this.key;
+ }
+ @Override
+ public Integer getValue() {
+ return this.value;
+ }
}
- @Override
- public Integer getValue() {
- return this.value;
+
+ static class GrailComparator implements Comparator {
+ @Override
+ public int compare(GrailPair o1, GrailPair o2) {
+ if (o1.getKey() < o2.getKey()) return -1;
+ else if(o1.getKey() > o2.getKey()) return 1;
+ else return 0;
+ }
}
-}
-class GrailComparator implements Comparator {
- @Override
- public int compare(GrailPair o1, GrailPair o2) {
- if (o1.getKey() < o2.getKey()) return -1;
- else if(o1.getKey() > o2.getKey()) return 1;
- else return 0;
+ private int seed;
+
+ private GrailPair[] keyArray;
+ private GrailPair[] referenceArray;
+ private Integer[] valueArray;
+
+ private String failReason;
+
+ public Tester(int maxLength, int maxKeyCount) {
+ this.seed = 100000001;
+ this.keyArray = new GrailPair[maxLength];
+ this.valueArray = new Integer[maxKeyCount];
}
-}
-public class Tester {
+ private int getRandomNumber(int key) {
+ this.seed = (this.seed * 1234565) + 1;
+ return (int) (((long) (this.seed & 0x7fffffff) * key) >> 31);
+ }
+
+ private void generateTestArray(int start, int length, int keyCount) {
+ for(int i = 0; i < keyCount; i++) {
+ this.valueArray[i] = 0;
+ }
+
+ for(int i = start; i < start + length; i++) {
+ if(keyCount != 0) {
+ int key = this.getRandomNumber(keyCount);
+ this.keyArray[i] = new GrailPair(key, this.valueArray[key]);
+ this.valueArray[key]++;
+ }
+ else {
+ this.keyArray[i] = new GrailPair(this.getRandomNumber(1000000000), 0);
+ }
+ }
+ }
- public Tester() {
- new HolyGrailSort(new GrailComparator());
+ private boolean testArray(int start, int length, GrailComparator test) {
+ for(int i = start + 1; i < start + length; i++) {
+ int compare = test.compare(this.keyArray[i - 1],
+ this.keyArray[i ]);
+ if(compare > 0) {
+ this.failReason = "testArray[" + (i - 1) + "] and testArray[" + i + "] are out-of-order\n";
+ return false;
+ }
+ else if(compare == 0 && this.keyArray[i - 1].getValue() > this.keyArray[i].getValue()) {
+ this.failReason = "testArray[" + (i - 1) + "] and testArray[" + i + "] are unstable\n";
+ return false;
+ }
+ else if(!this.keyArray[i - 1].equals(this.referenceArray[i - 1])) {
+ this.failReason = "testArray[" + (i - 1) + "] does not match the reference array\n";
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void checkAlgorithm(int start, int length, int keyCount, boolean grailSort, int grailBufferType, String grailStrategy, GrailComparator test) throws SortFailedException {
+ this.generateTestArray(start, length, keyCount);
+ this.referenceArray = Arrays.copyOf(this.keyArray, start + length);
+
+ String grailType = "w/o External Buffer";
+ if(grailBufferType == 1) {
+ grailType = "w/ O(1) Buffer ";
+ }
+ else if(grailBufferType == 2) {
+ grailType = "w/ O(sqrt n) Buffer";
+ }
+
+ if(grailSort) {
+ System.out.println("\n* Grailsort " + grailType + ", " + grailStrategy + " \n* start = " + start + ", length = " + length + ", unique items = " + keyCount);
+ }
+ else {
+ System.out.println("\n* Arrays.sort (Timsort) \n* start = " + start + ", length = " + length + ", unique items = " + keyCount);
+ }
+
+ long begin;
+ long time;
+
+ if(grailSort) {
+ HolyGrailSort grail = new HolyGrailSort<>(test);
+
+ GrailPair[] buffer = null;
+ int bufferLen = 0;
+
+ // Grailsort with static buffer
+ if(grailBufferType == 1) {
+ buffer = (GrailPair[]) Array.newInstance(this.keyArray.getClass().getComponentType(), HolyGrailSort.STATIC_EXT_BUFFER_LEN);
+ bufferLen = HolyGrailSort.STATIC_EXT_BUFFER_LEN;
+ }
+ // Grailsort with dynamic buffer
+ else if(grailBufferType == 2) {
+ bufferLen = 1;
+ while((bufferLen * bufferLen) < length) {
+ bufferLen *= 2;
+ }
+ buffer = (GrailPair[]) Array.newInstance(this.keyArray.getClass().getComponentType(), bufferLen);
+ }
+
+ begin = System.nanoTime();
+ grail.commonSort(this.keyArray, start, length, buffer, bufferLen);
+ time = System.nanoTime() - begin;
+ }
+ else {
+ begin = System.nanoTime();
+ Arrays.sort(this.keyArray, start, start + length, test);
+ time = System.nanoTime() - begin;
+ }
+
+ System.out.print("- Sorted in " + time * 1e-6d + "ms...");
+ Arrays.sort(this.referenceArray, start, start + length, test);
+
+ boolean success = this.testArray(start, length, test);
+ if(success) {
+ System.out.print(" and the sort was successful!\n");
+ }
+ else {
+ System.out.print(" but the sort was NOT successful!!\nReason: " + this.failReason);
+ throw new SortFailedException();
+ }
+
+ // Sometimes the garbage collector wasn't cooperating.
+ Arrays.fill(this.keyArray, null);
+ Arrays.fill(this.valueArray, null);
+ Arrays.fill(this.referenceArray, null);
+ System.gc();
+ }
+
+ private void checkBoth(int start, int length, int keyCount, String grailStrategy, GrailComparator test) throws SortFailedException {
+ int tempSeed = this.seed;
+ if(!grailStrategy.equals("Opti.Gnome")) {
+ for(int i = 0; i < 3; i++) {
+ this.checkAlgorithm(start, length, keyCount, true, i, grailStrategy, test);
+ this.seed = tempSeed;
+ }
+ }
+ else {
+ this.checkAlgorithm(start, length, keyCount, true, 0, grailStrategy, test);
+ this.seed = tempSeed;
+ }
+
+ this.checkAlgorithm(start, length, keyCount, false, 0, null, test);
}
public static void main(String[] args) {
- new Tester();
+ int maxLength = 50000000;
+ int maxKeyCount = 25000000;
+
+ Tester testClass = new Tester(maxLength, maxKeyCount);
+ GrailComparator testCompare = new GrailComparator();
+
+ System.out.println("Warming-up the JVM...");
+
+ try {
+ for(int u = 5; u <= (maxLength / 100); u *= 10) {
+ for(int v = 2; v <= u && v <= (maxKeyCount / 100); v *= 2) {
+ for(int i = 0; i < 3; i++) {
+ testClass.checkAlgorithm(0, u, v - 1, true, i, "All Strategies", testCompare);
+ }
+ }
+ }
+
+ System.out.println("\n*** Testing Grailsort against Timsort ***");
+
+ testClass.checkBoth( 0, 15, 4, "Opti.Gnome", testCompare);
+ testClass.checkBoth( 0, 15, 8, "Opti.Gnome", testCompare);
+ testClass.checkBoth( 7, 8, 4, "Opti.Gnome", testCompare);
+
+ testClass.checkBoth( 0, 1000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 0, 1000000, 1023, "Strategy 2", testCompare);
+ testClass.checkBoth( 0, 1000000, 500000, "Strategy 1", testCompare);
+ testClass.checkBoth( 500000, 500000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 500000, 500000, 511, "Strategy 2", testCompare);
+ testClass.checkBoth( 500000, 500000, 250000, "Strategy 1", testCompare);
+
+ testClass.checkBoth( 0, 10000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 0, 10000000, 4095, "Strategy 2", testCompare);
+ testClass.checkBoth( 0, 10000000, 5000000, "Strategy 1", testCompare);
+ testClass.checkBoth( 5000000, 5000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 5000000, 5000000, 2047, "Strategy 2", testCompare);
+ testClass.checkBoth( 5000000, 5000000, 2500000, "Strategy 1", testCompare);
+
+ testClass.checkBoth( 0, 50000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 0, 50000000, 16383, "Strategy 2", testCompare);
+ testClass.checkBoth( 0, 50000000, 25000000, "Strategy 1", testCompare);
+ testClass.checkBoth(25000000, 25000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth(25000000, 25000000, 8191, "Strategy 2", testCompare);
+ testClass.checkBoth(25000000, 25000000, 12500000, "Strategy 1", testCompare);
+
+
+ testClass.checkBoth(25000000, 25000000, 12500000, "Strategy 1", testCompare);
+ testClass.checkBoth(25000000, 25000000, 8191, "Strategy 2", testCompare);
+ testClass.checkBoth(25000000, 25000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 0, 50000000, 25000000, "Strategy 1", testCompare);
+ testClass.checkBoth( 0, 50000000, 16383, "Strategy 2", testCompare);
+ testClass.checkBoth( 0, 50000000, 3, "Strategy 3", testCompare);
+
+ testClass.checkBoth( 5000000, 5000000, 2500000, "Strategy 1", testCompare);
+ testClass.checkBoth( 5000000, 5000000, 2047, "Strategy 2", testCompare);
+ testClass.checkBoth( 5000000, 5000000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 0, 10000000, 5000000, "Strategy 1", testCompare);
+ testClass.checkBoth( 0, 10000000, 4095, "Strategy 2", testCompare);
+ testClass.checkBoth( 0, 10000000, 3, "Strategy 3", testCompare);
+
+ testClass.checkBoth( 500000, 500000, 250000, "Strategy 1", testCompare);
+ testClass.checkBoth( 500000, 500000, 511, "Strategy 2", testCompare);
+ testClass.checkBoth( 500000, 500000, 3, "Strategy 3", testCompare);
+ testClass.checkBoth( 0, 1000000, 500000, "Strategy 1", testCompare);
+ testClass.checkBoth( 0, 1000000, 1023, "Strategy 2", testCompare);
+ testClass.checkBoth( 0, 1000000, 3, "Strategy 3", testCompare);
+
+ testClass.checkBoth( 7, 8, 4, "Opti.Gnome", testCompare);
+ testClass.checkBoth( 0, 15, 8, "Opti.Gnome", testCompare);
+ testClass.checkBoth( 0, 15, 4, "Opti.Gnome", testCompare);
+
+ System.out.println("\nAll tests passed successfully!!");
+ } catch (SortFailedException e) {
+ System.out.println("\nTesting failed!!\n");
+ System.exit(1);
+ }
}
}