mirror of
https://gitlab.uni-marburg.de/langbeid/powersort.git
synced 2025-01-21 19:50:35 +01:00
Merge remote-tracking branch 'origin/main'
# Conflicts: # app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java
This commit is contained in:
commit
592eda73a6
@ -26,6 +26,7 @@ package de.uni_marburg.powersort.FinnSort;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import static java.lang.Math.pow;
|
import static java.lang.Math.pow;
|
||||||
@ -68,13 +69,13 @@ public class FasterFinnSort<T> {
|
|||||||
* This is the minimum sized sequence that will be merged. Shorter
|
* This is the minimum sized sequence that will be merged. Shorter
|
||||||
* sequences will be lengthened by calling binarySort. If the entire
|
* sequences will be lengthened by calling binarySort. If the entire
|
||||||
* array is less than this length, no merges will be performed.
|
* array is less than this length, no merges will be performed.
|
||||||
*
|
* <p>
|
||||||
* This constant should be a power of two. It was 64 in Tim Peter's C
|
* This constant should be a power of two. It was 64 in Tim Peter's C
|
||||||
* implementation, but 32 was empirically determined to work better in
|
* implementation, but 32 was empirically determined to work better in
|
||||||
* this implementation. In the unlikely event that you set this constant
|
* this implementation. In the unlikely event that you set this constant
|
||||||
* to be a number that's not a power of two, you'll need to change the
|
* to be a number that's not a power of two, you'll need to change the
|
||||||
* {@link #minRunLength} computation.
|
* {@link #minRunLength} computation.
|
||||||
*
|
* <p>
|
||||||
* If you decrease this constant, you must change the stackLen
|
* If you decrease this constant, you must change the stackLen
|
||||||
* computation in the TimSort constructor, or you risk an
|
* computation in the TimSort constructor, or you risk an
|
||||||
* ArrayOutOfBounds exception. See listsort.txt for a discussion
|
* ArrayOutOfBounds exception. See listsort.txt for a discussion
|
||||||
@ -87,6 +88,7 @@ public class FasterFinnSort<T> {
|
|||||||
* The array being sorted.
|
* The array being sorted.
|
||||||
*/
|
*/
|
||||||
private final T[] a;
|
private final T[] a;
|
||||||
|
private final int rangeSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The comparator for this sort.
|
* The comparator for this sort.
|
||||||
@ -128,9 +130,9 @@ public class FasterFinnSort<T> {
|
|||||||
* A stack of pending runs yet to be merged. Run i starts at
|
* A stack of pending runs yet to be merged. Run i starts at
|
||||||
* address base[i] and extends for len[i] elements. It's always
|
* address base[i] and extends for len[i] elements. It's always
|
||||||
* true (so long as the indices are in bounds) that:
|
* true (so long as the indices are in bounds) that:
|
||||||
*
|
* <p>
|
||||||
* runBase[i] + runLen[i] == runBase[i + 1]
|
* runBase[i] + runLen[i] == runBase[i + 1]
|
||||||
*
|
* <p>
|
||||||
* so we could cut the storage for this, but it's a minor amount,
|
* so we could cut the storage for this, but it's a minor amount,
|
||||||
* and keeping all the info explicit simplifies the code.
|
* and keeping all the info explicit simplifies the code.
|
||||||
*/
|
*/
|
||||||
@ -148,10 +150,10 @@ public class FasterFinnSort<T> {
|
|||||||
* @param workBase origin of usable space in work array
|
* @param workBase origin of usable space in work array
|
||||||
* @param workLen usable size of work array
|
* @param workLen usable size of work array
|
||||||
*/
|
*/
|
||||||
FasterFinnSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
|
FasterFinnSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen, int rangeSize) {
|
||||||
this.a = a;
|
this.a = a;
|
||||||
this.c = c;
|
this.c = c;
|
||||||
|
this.rangeSize = rangeSize;
|
||||||
// Allocate temp storage (which may be increased later if necessary)
|
// Allocate temp storage (which may be increased later if necessary)
|
||||||
int len = a.length;
|
int len = a.length;
|
||||||
int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
|
int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
|
||||||
@ -163,8 +165,7 @@ public class FasterFinnSort<T> {
|
|||||||
tmp = newArray;
|
tmp = newArray;
|
||||||
tmpBase = 0;
|
tmpBase = 0;
|
||||||
tmpLen = tlen;
|
tmpLen = tlen;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tmp = work;
|
tmp = work;
|
||||||
tmpBase = workBase;
|
tmpBase = workBase;
|
||||||
tmpLen = workLen;
|
tmpLen = workLen;
|
||||||
@ -216,12 +217,12 @@ public class FasterFinnSort<T> {
|
|||||||
public static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
|
public static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
|
||||||
T[] work, int workBase, int workLen) {
|
T[] work, int workBase, int workLen) {
|
||||||
assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
|
assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
|
||||||
|
|
||||||
int nRemaining = hi - lo;
|
int nRemaining = hi - lo;
|
||||||
if (nRemaining < 2)
|
if (nRemaining < 2)
|
||||||
return; // Arrays of size 0 and 1 are always sorted
|
return; // Arrays of size 0 and 1 are always sorted
|
||||||
|
|
||||||
// If array is small, do a "mini-TimSort" with no merges
|
// If array is small, do a "mini-TimSort" with no merges
|
||||||
|
|
||||||
if (nRemaining < MIN_MERGE) {
|
if (nRemaining < MIN_MERGE) {
|
||||||
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
|
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
|
||||||
binarySort(a, lo, hi, lo + initRunLen, c);
|
binarySort(a, lo, hi, lo + initRunLen, c);
|
||||||
@ -233,8 +234,8 @@ public class FasterFinnSort<T> {
|
|||||||
* extending short natural runs to minRun elements, and merging runs
|
* extending short natural runs to minRun elements, and merging runs
|
||||||
* to maintain stack invariant.
|
* to maintain stack invariant.
|
||||||
*/
|
*/
|
||||||
FasterFinnSort<T> ts = new FasterFinnSort<>(a, c, work, workBase, workLen);
|
FasterFinnSort<T> fs = new FasterFinnSort<>(a, c, work, workBase, workLen, hi - lo);
|
||||||
int minRun = ts.minRunLength(nRemaining);
|
int minRun = fs.minRunLength(nRemaining);
|
||||||
do {
|
do {
|
||||||
// Identify next run
|
// Identify next run
|
||||||
int runLen = countRunAndMakeAscending(a, lo, hi, c);
|
int runLen = countRunAndMakeAscending(a, lo, hi, c);
|
||||||
@ -247,8 +248,8 @@ public class FasterFinnSort<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push run onto pending-run stack, and maybe merge
|
// Push run onto pending-run stack, and maybe merge
|
||||||
ts.pushRun(lo, runLen, hi - lo);
|
fs.pushRun(lo, runLen);
|
||||||
ts.mergeCollapse();
|
fs.mergeCollapse();
|
||||||
|
|
||||||
// Advance to find next run
|
// Advance to find next run
|
||||||
lo += runLen;
|
lo += runLen;
|
||||||
@ -257,8 +258,8 @@ public class FasterFinnSort<T> {
|
|||||||
|
|
||||||
// Merge all remaining runs to complete sort
|
// Merge all remaining runs to complete sort
|
||||||
assert lo == hi;
|
assert lo == hi;
|
||||||
ts.mergeForceCollapse();
|
fs.mergeForceCollapse();
|
||||||
assert ts.stackSize == 1;
|
assert fs.stackSize == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,7 +267,7 @@ public class FasterFinnSort<T> {
|
|||||||
* insertion sort. This is the best method for sorting small numbers
|
* insertion sort. This is the best method for sorting small numbers
|
||||||
* of elements. It requires O(n log n) compares, but O(n^2) data
|
* of elements. It requires O(n log n) compares, but O(n^2) data
|
||||||
* movement (worst case).
|
* movement (worst case).
|
||||||
*
|
* <p>
|
||||||
* If the initial part of the specified range is already sorted,
|
* If the initial part of the specified range is already sorted,
|
||||||
* this method can take advantage of it: the method assumes that the
|
* this method can take advantage of it: the method assumes that the
|
||||||
* elements from index {@code lo}, inclusive, to {@code start},
|
* elements from index {@code lo}, inclusive, to {@code start},
|
||||||
@ -329,15 +330,15 @@ public class FasterFinnSort<T> {
|
|||||||
* Returns the length of the run beginning at the specified position in
|
* Returns the length of the run beginning at the specified position in
|
||||||
* the specified array and reverses the run if it is descending (ensuring
|
* the specified array and reverses the run if it is descending (ensuring
|
||||||
* that the run will always be ascending when the method returns).
|
* that the run will always be ascending when the method returns).
|
||||||
*
|
* <p>
|
||||||
* A run is the longest ascending sequence with:
|
* A run is the longest ascending sequence with:
|
||||||
*
|
* <p>
|
||||||
* a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
|
* a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
|
||||||
*
|
* <p>
|
||||||
* or the longest descending sequence with:
|
* or the longest descending sequence with:
|
||||||
*
|
* <p>
|
||||||
* a[lo] > a[lo + 1] > a[lo + 2] > ...
|
* a[lo] > a[lo + 1] > a[lo + 2] > ...
|
||||||
*
|
* <p>
|
||||||
* For its intended use in a stable mergesort, the strictness of the
|
* For its intended use in a stable mergesort, the strictness of the
|
||||||
* definition of "descending" is needed so that the call can safely
|
* definition of "descending" is needed so that the call can safely
|
||||||
* reverse a descending sequence without violating stability.
|
* reverse a descending sequence without violating stability.
|
||||||
@ -390,14 +391,14 @@ public class FasterFinnSort<T> {
|
|||||||
* Returns the minimum acceptable run length for an array of the specified
|
* Returns the minimum acceptable run length for an array of the specified
|
||||||
* length. Natural runs shorter than this will be extended with
|
* length. Natural runs shorter than this will be extended with
|
||||||
* {@link #binarySort}.
|
* {@link #binarySort}.
|
||||||
*
|
* <p>
|
||||||
* Roughly speaking, the computation is:
|
* Roughly speaking, the computation is:
|
||||||
*
|
* <p>
|
||||||
* If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
|
* If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
|
||||||
* Else if n is an exact power of 2, return MIN_MERGE/2.
|
* Else if n is an exact power of 2, return MIN_MERGE/2.
|
||||||
* Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
|
* Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
|
||||||
* is close to, but strictly less than, an exact power of 2.
|
* is close to, but strictly less than, an exact power of 2.
|
||||||
*
|
* <p>
|
||||||
* For the rationale, see listsort.txt.
|
* For the rationale, see listsort.txt.
|
||||||
*
|
*
|
||||||
* @param n the length of the array to be sorted
|
* @param n the length of the array to be sorted
|
||||||
@ -419,24 +420,24 @@ public class FasterFinnSort<T> {
|
|||||||
* @param runBase index of the first element in the run
|
* @param runBase index of the first element in the run
|
||||||
* @param runLen the number of elements in the run
|
* @param runLen the number of elements in the run
|
||||||
*/
|
*/
|
||||||
void pushRun(int runBase, int runLen, int rangeSize) {
|
void pushRun(int runBase, int runLen) {
|
||||||
this.runBase[stackSize] = runBase;
|
this.runBase[stackSize] = runBase;
|
||||||
this.runLen[stackSize] = runLen;
|
this.runLen[stackSize] = runLen;
|
||||||
this.runPower[stackSize] = power(stackSize, rangeSize);
|
this.runPower[stackSize] = power(stackSize);
|
||||||
stackSize++;
|
stackSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Examines the stack of runs waiting to be merged and merges adjacent runs
|
* Examines the stack of runs waiting to be merged and merges adjacent runs
|
||||||
* until the stack invariants are reestablished:
|
* until the stack invariants are reestablished:
|
||||||
*
|
* <p>
|
||||||
* 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
|
* 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
|
||||||
* 2. runLen[i - 2] > runLen[i - 1]
|
* 2. runLen[i - 2] > runLen[i - 1]
|
||||||
*
|
* <p>
|
||||||
* This method is called each time a new run is pushed onto the stack,
|
* This method is called each time a new run is pushed onto the stack,
|
||||||
* so the invariants are guaranteed to hold for i < stackSize upon
|
* so the invariants are guaranteed to hold for i < stackSize upon
|
||||||
* entry to the method.
|
* entry to the method.
|
||||||
*
|
* <p>
|
||||||
* Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer,
|
* Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer,
|
||||||
* Richard Bubel and Reiner Hahnle, this is fixed with respect to
|
* Richard Bubel and Reiner Hahnle, this is fixed with respect to
|
||||||
* the analysis in "On the Worst-Case Complexity of TimSort" by
|
* the analysis in "On the Worst-Case Complexity of TimSort" by
|
||||||
@ -444,16 +445,35 @@ public class FasterFinnSort<T> {
|
|||||||
*/
|
*/
|
||||||
void mergeCollapse() {
|
void mergeCollapse() {
|
||||||
while (stackSize > 1) {
|
while (stackSize > 1) {
|
||||||
int n = stackSize - 2;
|
if (runPower[stackSize - 1] < runPower[stackSize - 2]) {
|
||||||
if (n > 0 && runPower[n + 1] < runPower[n]) {
|
mergeAt(stackSize - 3);
|
||||||
mergeAt(n);
|
|
||||||
} else {
|
} else {
|
||||||
break; // Invariant is established
|
break; // Invariant is established
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
int power(int stackSize, int rangeSize) {
|
private int power(int stackSize) {
|
||||||
|
if (stackSize == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// int = (right - left + 1); = RangeSize
|
||||||
|
long l = runLen[stackSize - 1]; // + (long) runBase[stackSize]; // - ((long) left << 1); // 2*middleA
|
||||||
|
long r = runLen[stackSize]; // - ((long) left << 1); // 2*middleB
|
||||||
|
int a = (int) ((l << 30) / rangeSize); // middleA / 2n
|
||||||
|
int b = (int) ((r << 30) / rangeSize); // middleB / 2n
|
||||||
|
return Integer.numberOfLeadingZeros(a ^ b);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int power(int stackSize) {
|
||||||
|
/*
|
||||||
|
System.out.println(Arrays.toString(runBase));
|
||||||
|
System.out.println(Arrays.toString(runLen));
|
||||||
|
System.out.println(Arrays.toString(runPower));
|
||||||
|
System.out.println(stackSize);
|
||||||
|
System.out.println(rangeSize);
|
||||||
|
System.out.println();
|
||||||
|
*/
|
||||||
if (stackSize == 0)
|
if (stackSize == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -465,18 +485,50 @@ public class FasterFinnSort<T> {
|
|||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
while (b < rangeSize) {
|
while (true) {
|
||||||
++result;
|
++result;
|
||||||
if (a >= rangeSize) {
|
if (a >= rangeSize) {
|
||||||
a -= rangeSize;
|
a -= rangeSize;
|
||||||
b -= rangeSize;
|
b -= rangeSize;
|
||||||
}
|
}
|
||||||
|
if (b >= rangeSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
a <<= 1;
|
a <<= 1;
|
||||||
b <<= 1;
|
b <<= 1;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public int power(int stackSize) {
|
||||||
|
|
||||||
|
System.out.println(Arrays.toString(runBase));
|
||||||
|
System.out.println(Arrays.toString(runLen));
|
||||||
|
System.out.println(Arrays.toString(runPower));
|
||||||
|
System.out.println(stackSize);
|
||||||
|
System.out.println(rangeSize);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
|
||||||
|
if (stackSize == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int n_1 = this.runLen[stackSize - 1];
|
||||||
|
int n_2 = this.runLen[stackSize];
|
||||||
|
|
||||||
|
double a = ((double) this.runBase[stackSize - 1] + 0.5d * n_1 - 1d) / this.rangeSize;
|
||||||
|
double b = ((double) this.runBase[stackSize] + 0.5d * n_2 - 1d) / this.rangeSize;
|
||||||
|
int l = 0;
|
||||||
|
while ((int) (a * pow(2, l)) == (int) (b * pow(2 ,l))) {
|
||||||
|
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Backup mergeCollapse() von TimSort:
|
Backup mergeCollapse() von TimSort:
|
||||||
|
|
||||||
@ -519,7 +571,7 @@ public class FasterFinnSort<T> {
|
|||||||
private void mergeAt(int i) {
|
private void mergeAt(int i) {
|
||||||
assert stackSize >= 2;
|
assert stackSize >= 2;
|
||||||
assert i >= 0;
|
assert i >= 0;
|
||||||
assert i == stackSize - 2 || i == stackSize - 3;
|
//assert i == stackSize - 3;
|
||||||
|
|
||||||
int base1 = runBase[i];
|
int base1 = runBase[i];
|
||||||
int len1 = runLen[i];
|
int len1 = runLen[i];
|
||||||
@ -533,12 +585,14 @@ public class FasterFinnSort<T> {
|
|||||||
* run now, also slide over the last run (which isn't involved
|
* run now, also slide over the last run (which isn't involved
|
||||||
* in this merge). The current run (i+1) goes away in any case.
|
* in this merge). The current run (i+1) goes away in any case.
|
||||||
*/
|
*/
|
||||||
runLen[i] = len1 + len2;
|
|
||||||
if (i == stackSize - 3) {
|
|
||||||
runBase[i + 1] = runBase[i + 2];
|
|
||||||
runLen[i + 1] = runLen[i + 2];
|
|
||||||
}
|
|
||||||
stackSize--;
|
stackSize--;
|
||||||
|
runLen[i] = len1 + len2;
|
||||||
|
|
||||||
|
// @TODO: Check power before pushing the run
|
||||||
|
runLen[i + 1] = runLen[i + 2];
|
||||||
|
runBase[i + 1] = runBase[i + 2];
|
||||||
|
runPower[i + 1] = runPower[i + 2];
|
||||||
|
//runPower[i] = power(i);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find where the first element of run2 goes in run1. Prior elements
|
* Find where the first element of run2 goes in run1. Prior elements
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package de.uni_marburg.powersort.FinnSort;
|
package de.uni_marburg.powersort.FinnSort;
|
||||||
|
|
||||||
class Run {
|
public class Run {
|
||||||
int start;
|
public int start;
|
||||||
int end;
|
public int end;
|
||||||
int power;
|
int power;
|
||||||
|
public int len;
|
||||||
|
|
||||||
public Run(int i, int j, int p) {
|
public Run(int i, int j, int p) {
|
||||||
start = i;
|
start = i;
|
||||||
end = j;
|
end = j;
|
||||||
power = p;
|
power = p;
|
||||||
|
len = end - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package de.uni_marburg.powersort.MSort;
|
package de.uni_marburg.powersort.MSort;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -29,9 +30,9 @@ public class IMPL_M_1 {
|
|||||||
*/
|
*/
|
||||||
protected static int MERGE_COST = 0;
|
protected static int MERGE_COST = 0;
|
||||||
|
|
||||||
public static void fillWithAscRunsHighToLow(List<Integer> A, int[] runLengths, int runLenFactor) {
|
public static void fillWithAscRunsHighToLow(Integer[] A, int[] runLengths, int runLenFactor) {
|
||||||
//A has a fixed size, but it doesn't have any meaningful values
|
//A has a fixed size, but it doesn't have any meaningful values
|
||||||
int n = A.size();
|
int n = A.length;
|
||||||
//This ensures that the sum of runLengths multiplied by runLenFactor equals the list size n. If not, an AssertionError is thrown.
|
//This ensures that the sum of runLengths multiplied by runLenFactor equals the list size n. If not, an AssertionError is thrown.
|
||||||
assert IntStream.of(runLengths).sum() * runLenFactor == n;
|
assert IntStream.of(runLengths).sum() * runLenFactor == n;
|
||||||
|
|
||||||
@ -39,34 +40,59 @@ public class IMPL_M_1 {
|
|||||||
//IntStream.of(runLengths).forEach(System.out::println);
|
//IntStream.of(runLengths).forEach(System.out::println);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
//putting i in set a, while a is always the last index of n
|
//putting i in set a, while a is always the last index of n
|
||||||
A.set(i, n - i);
|
A[i] = n - i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
//For each value l in the array runLengths, do the following
|
//For each value l in the array runLengths, do the following
|
||||||
// runLengths = {2, 3, 5}, the loop will run three times, with l taking values 2, 3, and 5 respectively.
|
// runLengths = {2, 3, 5}, the loop will run three times, with l taking values 2, 3, and 5 respectively.
|
||||||
|
int startIndex = 0;
|
||||||
for (int l : runLengths) {
|
for (int l : runLengths) {
|
||||||
int L = l * runLenFactor;
|
int L = l * runLenFactor;
|
||||||
List<Integer> sublist = A.subList(i, i + L);
|
// Sort the subarray from startIndex to startIndex+L manually
|
||||||
Collections.sort(sublist);
|
for (int i = startIndex; i < startIndex + L - 1; i++) {
|
||||||
i += L;
|
for (int j = startIndex; j < startIndex + L - 1 - (i - startIndex); j++) {
|
||||||
|
if (A[j] > A[j + 1]) {
|
||||||
|
// Swap elements
|
||||||
|
int temp = A[j];
|
||||||
|
A[j] = A[j + 1];
|
||||||
|
A[j + 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startIndex += L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static <T> List<T> merge(List<T> run1, List<T> run2, Comparator<? super T> c) {
|
static <T> T[] merge(T[] run1, T[] run2, Comparator<? super T> c) {
|
||||||
List<T> result = new ArrayList<>();
|
/**
|
||||||
while (!run1.isEmpty() && !run2.isEmpty()) {
|
* We need this because:
|
||||||
|
* In Java, you cannot create generic arrays directly (can't write new T[size])
|
||||||
|
* The workaround is to create an Object array and cast it to T[]
|
||||||
|
* This casting generates a warning because the compiler can't verify the type safety at runtime due to Java's type erasure
|
||||||
|
* **/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T[] result = (T[]) new Object[run1.length + run2.length];
|
||||||
|
int i = 0, j = 0, k = 0;
|
||||||
|
|
||||||
|
while (i < run1.length && j < run2.length) {
|
||||||
//This comparison only works if the lists are sorted
|
//This comparison only works if the lists are sorted
|
||||||
if (c.compare(run1.getFirst(),run2.getFirst()) < 0) {
|
if (c.compare(run1[i], run2[j]) <= 0) {
|
||||||
result.add(run1.removeFirst());
|
result[k++] = run1[i++];
|
||||||
} else {
|
} else {
|
||||||
result.add(run2.removeFirst());
|
result[k++] = run2[j++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// can be improved by finding out which one is empty and only add the other one
|
// can be improved by finding out which one is empty and only add the other one
|
||||||
result.addAll(run1);
|
// Copy remaining elements
|
||||||
result.addAll(run2);
|
while (i < run1.length) {
|
||||||
|
result[k++] = run1[i++];
|
||||||
|
}
|
||||||
|
while (j < run2.length) {
|
||||||
|
result[k++] = run2[j++];
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +111,7 @@ public class IMPL_M_1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static <T> void mergeInplace(T[] a, int i, int m, int j, Comparator<? super T> c) {
|
static <T> void mergeInplace(T[] a, int i, int m, int j, Comparator<? super T> c) {
|
||||||
// System.out.printf("Merge(%d, %d, %d)%n", i, m, j);
|
System.out.printf("Merge(%d, %d, %d)%n", i, m, j);
|
||||||
MERGE_COST += j - i;
|
MERGE_COST += j - i;
|
||||||
// Create temporary arrays for merging
|
// Create temporary arrays for merging
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -98,22 +124,11 @@ public class IMPL_M_1 {
|
|||||||
System.arraycopy(a, m, right, 0, j - m);
|
System.arraycopy(a, m, right, 0, j - m);
|
||||||
|
|
||||||
// Merge back to original array
|
// Merge back to original array
|
||||||
int k = i, l = 0, r = 0;
|
// Merge the runs
|
||||||
while (l < left.length && r < right.length) {
|
T[] merged = merge(left, right, c);
|
||||||
if (c.compare(left[l], right[r]) <= 0) {
|
|
||||||
a[k++] = left[l++];
|
|
||||||
} else {
|
|
||||||
a[k++] = right[r++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy remaining elements
|
//copy back to original array
|
||||||
while (l < left.length) {
|
System.arraycopy(merged, 0, a, i,merged.length);
|
||||||
a[k++] = left[l++];
|
|
||||||
}
|
|
||||||
while (r < right.length) {
|
|
||||||
a[k++] = right[r++];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ public class IMPL_M_2<T>{
|
|||||||
* of the minimum stack length required as a function of the length
|
* of the minimum stack length required as a function of the length
|
||||||
* of the array being sorted and the minimum merge sequence length.
|
* of the array being sorted and the minimum merge sequence length.
|
||||||
*/
|
*/
|
||||||
private static final int MIN_MERGE = 24;
|
private static final int MIN_MERGE = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The array being sorted.
|
* The array being sorted.
|
||||||
|
@ -7,6 +7,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.uni_marburg.powersort.benchmark.NaturalOrder;
|
||||||
|
|
||||||
public class PowerSortT {
|
public class PowerSortT {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -22,7 +24,7 @@ public class PowerSortT {
|
|||||||
|
|
||||||
// Test for fillWithAscRunsHighToLow
|
// Test for fillWithAscRunsHighToLow
|
||||||
public static void testFillWithAscRunsHighToLow() {
|
public static void testFillWithAscRunsHighToLow() {
|
||||||
List<Integer> A = new ArrayList<>(Collections.nCopies(10, 0));
|
Integer[] A = new Integer[10];
|
||||||
int[] runLengths = {2, 3, 5};
|
int[] runLengths = {2, 3, 5};
|
||||||
int runLenFactor = 1;
|
int runLenFactor = 1;
|
||||||
fillWithAscRunsHighToLow(A, runLengths, runLenFactor);
|
fillWithAscRunsHighToLow(A, runLengths, runLenFactor);
|
||||||
@ -31,24 +33,24 @@ public class PowerSortT {
|
|||||||
|
|
||||||
// Test for merge
|
// Test for merge
|
||||||
public static void testMerge() {
|
public static void testMerge() {
|
||||||
List<Integer> run1 = new ArrayList<>(Arrays.asList(1, 4, 6));
|
Integer[] run1 ={1,4,6};
|
||||||
List<Integer> run2 = new ArrayList<>(Arrays.asList(2, 3, 5));
|
Integer []run2 = {2, 3, 5};
|
||||||
// List<Integer> result = merge(run1, run2);
|
Integer[] result = merge(run1, run2, NaturalOrder.INSTANCE);
|
||||||
// System.out.println("Test merge: " + result);
|
System.out.println("Test merge: " + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for mergeInplace
|
// Test for mergeInplace
|
||||||
public static void testMergeInplace() {
|
public static void testMergeInplace() {
|
||||||
List<Integer> A = new ArrayList<>(Arrays.asList(1, 4, 6, 2, 3, 5));
|
Integer[] A = {1,4,6,2,3,5};
|
||||||
//mergeInplace(A, 0, 3, 6);
|
mergeInplace(A, 0, 3, 6,NaturalOrder.INSTANCE);
|
||||||
System.out.println("Test mergeInplace: " + A);
|
System.out.println("Test mergeInplace: " + A);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for extendRun
|
// Test for extendRun
|
||||||
public static void testExtendRun() {
|
public static void testExtendRun() {
|
||||||
List<Integer> A = new ArrayList<>(Arrays.asList(1, 2, 3, 6, 5, 4));
|
Integer [] A = {1, 2, 3, 6, 5, 4};
|
||||||
// int endIndex = extendRun(A, 0);
|
int endIndex = extendRun(A, 0,NaturalOrder.INSTANCE);
|
||||||
// System.out.println("Test extendRun (from 0): " + endIndex);
|
System.out.println("Test extendRun (from 0): " + endIndex);
|
||||||
System.out.println("Modified List: " + A);
|
System.out.println("Modified List: " + A);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,18 +74,18 @@ public class PowerSortT {
|
|||||||
|
|
||||||
// Test for mergeTopmost2
|
// Test for mergeTopmost2
|
||||||
public static void testMergeTopmost2() {
|
public static void testMergeTopmost2() {
|
||||||
List<Integer> A = new ArrayList<>(Arrays.asList(1, 3, 5, 2, 4, 6));
|
Integer[] A = {1, 3, 5, 2, 4, 6};
|
||||||
List<int[]> runs = new ArrayList<>();
|
List<int[]> runs = new ArrayList<>();
|
||||||
runs.add(new int[]{0, 3, 1});
|
runs.add(new int[]{0, 3, 1});
|
||||||
runs.add(new int[]{3, 3, 1});
|
runs.add(new int[]{3, 3, 1});
|
||||||
// mergeTopmost2(A, runs);
|
mergeTopmost2(A, runs,NaturalOrder.INSTANCE);
|
||||||
System.out.println("Test mergeTopmost2: " + A);
|
System.out.println("Test mergeTopmost2: " + A);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for powerSort
|
// Test for powerSort
|
||||||
public static void testPowerSort() {
|
public static void testPowerSort() {
|
||||||
List<Integer> A = new ArrayList<>(Arrays.asList(10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
|
Integer [] A = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||||
// powerSort(A);
|
powerSort(A, NaturalOrder.INSTANCE);
|
||||||
System.out.println("Test powerSort: " + A);
|
System.out.println("Test powerSort: " + A);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import de.uni_marburg.powersort.benchmark.NaturalOrder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static de.uni_marburg.powersort.MSort.IMPL_M_1.MERGE_COST;
|
import static de.uni_marburg.powersort.MSort.IMPL_M_1.MERGE_COST;
|
||||||
@ -19,26 +20,28 @@ class PowerSortTest {
|
|||||||
// extendRun(list, 0);
|
// extendRun(list, 0);
|
||||||
//System.out.println(list);
|
//System.out.println(list);
|
||||||
// example from slides he wrote this
|
// example from slides he wrote this
|
||||||
int[] runs = {5, 3, 3, 14, 1, 2};
|
// int[] runs = {5, 3, 3, 14, 1, 2};
|
||||||
runs = new int[]{9, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
|
int [] runs = new int[]{9, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
|
||||||
|
int totalSize = Arrays.stream(runs).sum();
|
||||||
|
|
||||||
List<Integer> a = new ArrayList<>(IntStream.range(0, Arrays.stream(runs).sum()).boxed().collect(Collectors.toList()));
|
Integer[] a = new Integer[totalSize];
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
fillWithAscRunsHighToLow(a, runs, 1);
|
fillWithAscRunsHighToLow(a, runs, 1);
|
||||||
MERGE_COST = 0;
|
MERGE_COST = 0;
|
||||||
System.out.println("Sorting with Powersort:");
|
System.out.println("Sorting with Powersort:");
|
||||||
//powerSort(a);
|
powerSort(a,NaturalOrder.INSTANCE);
|
||||||
|
System.out.println("Sorted Array"+Arrays.toString(a));
|
||||||
System.out.println("Merge cost: " + MERGE_COST);
|
System.out.println("Merge cost: " + MERGE_COST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWithFinnInputList() {
|
public void testWithFinnInputList() {
|
||||||
List<Integer> numbers = List.of(new Integer[] {24, 25, 26, 27, 28, 21, 22, 23, 18, 19, 20, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 3, 1, 2});
|
Integer [] numbers = new Integer[] {24, 25, 26, 27, 28, 21, 22, 23, 18, 19, 20, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 3, 1, 2};
|
||||||
|
|
||||||
// powerSort(numbers);
|
|
||||||
System.out.println("Result: ");
|
|
||||||
System.out.println(new ArrayList<>(List.of(numbers)));
|
|
||||||
|
|
||||||
|
System.out.println("Original array"+Arrays.toString(numbers));
|
||||||
|
powerSort(numbers, NaturalOrder.INSTANCE);
|
||||||
|
System.out.println("Result: "+Arrays.toString(numbers));
|
||||||
|
// System.out.println(new ArrayList<>(List.of(numbers)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,77 @@
|
|||||||
package de.uni_marburg.powersort.sort;
|
package de.uni_marburg.powersort.sort;
|
||||||
|
|
||||||
|
import de.uni_marburg.powersort.FinnSort.FasterFinnSort;
|
||||||
|
import de.uni_marburg.powersort.FinnSort.Run;
|
||||||
|
import de.uni_marburg.powersort.benchmark.NaturalOrder;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import static java.lang.Math.pow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class FasterFinnSortTest extends AbstractSortTest {
|
public class FasterFinnSortTest extends AbstractSortTest {
|
||||||
FasterFinnSortTest() {
|
FasterFinnSortTest() {
|
||||||
sortAlg = SortEnum.FASTER_FINN_SORT;
|
sortAlg = SortEnum.FASTER_FINN_SORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeOrder() {
|
||||||
|
Integer[] input = {24,25,26,27,28,21,22,23,18,19,20,4,5,6,7,8,9,10,11,12,13,14,15,16,17,3,1,2};
|
||||||
|
FasterFinnSort.sort(input, 0, input.length, NaturalOrder.INSTANCE,null, 0, 0);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void powerTest() {
|
||||||
|
Run run1 = new Run(0, 10, 0);
|
||||||
|
Run run2 = new Run(10, 20, 0);
|
||||||
|
|
||||||
|
for (int i = 20; i < 10100; i++) {
|
||||||
|
System.out.println(i);
|
||||||
|
//assertEquals(integerPower(run1, run2, i), power(run1, run2, i));
|
||||||
|
assertEquals(power(run1, run2, i),
|
||||||
|
power2(run1, run2, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private static int integerPower(Run run1, Run run2, int n) {
|
||||||
|
|
||||||
|
int n_1 = run1.len;
|
||||||
|
int n_2 = run2.len;
|
||||||
|
|
||||||
|
int a = 2 * run1.start + n_1 - 1;
|
||||||
|
int b = a + n_1 + n_2;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
while (a * pow(2, result) == b * pow(2, result)) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private static int power(Run run1, Run run2, int n) {
|
||||||
|
/*
|
||||||
|
if (run1.start == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
int n_1 = run1.end - run1.start;
|
||||||
|
int n_2 = run2.end - run2.start;
|
||||||
|
double a = ((double) run1.start + 0.5d * n_1) / n;
|
||||||
|
double b = ((double) run2.start + 0.5d * n_2) / n;
|
||||||
|
int l = 1;
|
||||||
|
while ((int) (a * pow(2, l)) == (int) (b * pow(2 ,l))) {
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int power2(Run run1, Run run2, int n) {
|
||||||
|
long l = (long) run1.start + (long) run2.start; // 2*middleA
|
||||||
|
long r = (long) run2.start + (long) run2.end + 1; // 2*middleB
|
||||||
|
int a = (int) ((l << 30) / n); // middleA / 2n
|
||||||
|
int b = (int) ((r << 30) / n); // middleB / 2n
|
||||||
|
return Integer.numberOfLeadingZeros(a ^ b);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user