Changed FasterFinnSort to use the PowerSort merge policy

This commit is contained in:
finnm 2025-01-05 14:26:07 +01:00
parent c8bed52bf6
commit 4268315f06

View File

@ -28,6 +28,8 @@ package de.uni_marburg.powersort.FinnSort;
import java.util.Comparator;
import static java.lang.Math.pow;
/**
* A stable, adaptive, iterative mergesort that requires far fewer than
* n lg(n) comparisons when running on partially sorted arrays, while
@ -61,7 +63,7 @@ import java.util.Comparator;
*
* @author Josh Bloch
*/
class FasterFinnSort<T> {
public class FasterFinnSort<T> {
/**
* This is the minimum sized sequence that will be merged. Shorter
* sequences will be lengthened by calling binarySort. If the entire
@ -135,6 +137,7 @@ class FasterFinnSort<T> {
private int stackSize = 0; // Number of pending runs on stack
private final int[] runBase;
private final int[] runLen;
private final int[] runPower;
/**
* Creates a TimSort instance to maintain the state of an ongoing sort.
@ -186,6 +189,7 @@ class FasterFinnSort<T> {
len < 119151 ? 24 : 49);
runBase = new int[stackLen];
runLen = new int[stackLen];
runPower = new int[stackLen];
}
/*
@ -209,7 +213,7 @@ class FasterFinnSort<T> {
* @param workLen usable size of work array
* @since 1.8
*/
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) {
assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
@ -243,7 +247,7 @@ class FasterFinnSort<T> {
}
// Push run onto pending-run stack, and maybe merge
ts.pushRun(lo, runLen);
ts.pushRun(lo, runLen, hi - lo);
ts.mergeCollapse();
// Advance to find next run
@ -415,9 +419,10 @@ class FasterFinnSort<T> {
* @param runBase index of the first element in the run
* @param runLen the number of elements in the run
*/
private void pushRun(int runBase, int runLen) {
private void pushRun(int runBase, int runLen, int rangeSize) {
this.runBase[stackSize] = runBase;
this.runLen[stackSize] = runLen;
this.runPower[stackSize] = power(stackSize, rangeSize);
stackSize++;
}
@ -440,16 +445,29 @@ class FasterFinnSort<T> {
private void mergeCollapse() {
while (stackSize > 1) {
int n = stackSize - 2;
if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] ||
n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) {
if (runLen[n - 1] < runLen[n + 1])
n--;
} else if (n < 0 || runLen[n] > runLen[n + 1]) {
if (n > 0 && runPower[n + 1] < runPower[n]) {
mergeAt(n);
} else {
break; // Invariant is established
}
mergeAt(n);
}
}
private int power(int stackSize, int rangeSize) {
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) / rangeSize;
double b = ((double) this.runBase[stackSize] + 0.5d * n_2 - 1d) / rangeSize;
int l = 0;
while ((int) (a * pow(2, l)) == (int) (b * pow(2 ,l))) {
l++;
}
return l;
}
/*
Backup mergeCollapse() von TimSort: