creating IMPL_M_4 and getting better performance than TimSort in every case

This commit is contained in:
M-H9 2025-01-28 15:12:38 +01:00
parent dec8585ab4
commit 6694a076e5
7 changed files with 1648 additions and 895 deletions

View File

@ -111,7 +111,7 @@ public class IMPL_M_1 {
}
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;
// Create temporary arrays for merging
@SuppressWarnings("unchecked")
@ -131,7 +131,6 @@ public class IMPL_M_1 {
System.arraycopy(merged, 0, a, i,merged.length);
}
static <T> int extendRun(T [] a, int i, Comparator<? super T> c) {
// if i was the element before end so just return the last element
if (i == a.length - 1) {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
package de.uni_marburg.powersort.MSort;
import java.util.Arrays;
import java.util.Comparator;
public class IMPL_M_3 {
private static final int MIN_MERGE = 32;
private static final int MIN_GALLOP = 7;
private IMPL_M_3() {
}
public static void fillWithAscRunsHighToLow(Integer[] A, int[] runLengths, int runLenFactor) {
int n = A.length;
assert Arrays.stream(runLengths).sum() * runLenFactor == n;
for (int i = 0; i < n; i++) {
A[i] = n - i;
}
int startIndex = 0;
for (int l : runLengths) {
int L = l * runLenFactor;
Arrays.sort(A, startIndex, startIndex + L);
startIndex += L;
}
}
private static <T> int extendRun(T[] a, int i, Comparator<? super T> c) {
if (i >= a.length - 1) {
return a.length; // Return the end of the array
}
int j = i + 1;
boolean ascending = c.compare(a[i], a[j]) <= 0;
while (j < a.length && c.compare(a[j - 1], a[j]) == (ascending ? -1 : 1)) {
j++;
}
if (!ascending) {
reverseRange(a, i, j);
}
return j;
}
private static <T> void reverseRange(T[] a, int start, int end) {
end--;
while (start < end) {
T temp = a[start];
a[start++] = a[end];
a[end--] = temp;
}
}
private static <T> void mergeInplace(T[] a, int i, int m, int j, Comparator<? super T> c, T[] temp) {
int leftSize = m - i;
int rightSize = j - m;
// Validate indices
if (leftSize < 0 || rightSize < 0) {
throw new IllegalArgumentException("Invalid indices: leftSize=" + leftSize + ", rightSize=" + rightSize);
}
if (leftSize < 0) {
throw new IllegalArgumentException("Invalid indices: leftSize is negative");
}
// Ensure the temporary array is large enough
if (temp.length < leftSize) {
temp = Arrays.copyOf(temp, leftSize);
}
System.arraycopy(a, i, temp, 0, leftSize);
int li = 0, ri = m, k = i;
int gallopCount = 0;
while (li < leftSize && ri < j) {
if (c.compare(temp[li], a[ri]) <= 0) {
a[k++] = temp[li++];
gallopCount++;
} else {
a[k++] = a[ri++];
gallopCount = 0;
}
if (gallopCount >= MIN_GALLOP) {
gallopCount = 0;
while (li < leftSize && ri < j) {
if (c.compare(temp[li], a[ri]) <= 0) {
a[k++] = temp[li++];
} else {
a[k++] = a[ri++];
}
}
break;
}
}
while (li < leftSize) a[k++] = temp[li++];
while (ri < j) a[k++] = a[ri++];
}
public static <T> void powerSort(T[] a, Comparator<? super T> c) {
int n = a.length;
if (n < MIN_MERGE) {
Arrays.sort(a, c);
return;
}
// Initialize temporary array with a reasonable size
T[] temp = (T[]) new Object[Math.min(n, MIN_MERGE)];
int[] runStack = new int[40];
int stackSize = 0;
int i = 0;
while (i < n) {
int j = extendRun(a, i, c);
// Ensure j > i
if (j <= i) {
throw new IllegalStateException("Invalid run: j <= i, i=" + i + ", j=" + j);
}
int[] newRun = new int[]{i, j - i};
// Validate new run
if (newRun[0] >= newRun[1]) {
throw new IllegalArgumentException("Invalid run: start index >= length, i=" + i + ", j=" + j);
}
i = j;
if (stackSize > 0) {
int[] prevRun = new int[]{runStack[stackSize - 2], runStack[stackSize - 1]};
int p = power(prevRun, newRun, n);
while (stackSize > 0 && p <= runStack[stackSize - 1]) {
mergeInplace(a, runStack[stackSize - 2], runStack[stackSize - 1], i, c, temp);
stackSize -= 2;
}
}
runStack[stackSize++] = newRun[0];
runStack[stackSize++] = newRun[1];
}
while (stackSize > 2) {
mergeInplace(a, runStack[stackSize - 4], runStack[stackSize - 3], n, c, temp);
stackSize -= 2;
}
}
private static int power(int[] run1, int[] run2, int n) {
int i1 = run1[0], n1 = run1[1];
int i2 = run2[0], n2 = run2[1];
int a = 2 * i1 + n1;
int b = a + n1 + n2;
int l = 0;
while (true) {
l++;
if (a >= n) {
a -= n;
b -= n;
} else if (b >= n) {
break;
}
a <<= 1;
b <<= 1;
}
return l;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@ import de.uni_marburg.powersort.FinnSort.FinnSort;
import de.uni_marburg.powersort.FinnSort.FasterFinnSort;
import de.uni_marburg.powersort.MSort.IMPL_M_1;
import de.uni_marburg.powersort.MSort.IMPL_M_2;
import de.uni_marburg.powersort.MSort.IMPL_M_3;
import de.uni_marburg.powersort.MSort.IMPL_M_4;
import de.uni_marburg.powersort.benchmark.NaturalOrder;
import de.uni_marburg.powersort.sort.dpqs.DualPivotQuicksort;
@ -14,11 +16,14 @@ public enum SortEnum {
FINN_SORT,
IMPL_M_10,
IMPL_M_20,
IMPL_M_30,
IMPL_M_40,
DPQS,
QUICK_SORT,
MERGE_SORT,
BUBBLE_SORT;
public SortImpl getSortImpl() {
return switch (this) {
case BUBBLE_SORT -> array -> BubbleSort.sort(array, NaturalOrder.INSTANCE);
@ -28,7 +33,9 @@ public enum SortEnum {
case TIM_SORT -> array -> TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0);
case FINN_SORT -> array -> FinnSort.sort(array, NaturalOrder.INSTANCE);
case IMPL_M_10 -> array -> IMPL_M_1.powerSort(array,NaturalOrder.INSTANCE);
case IMPL_M_20 -> array -> IMPL_M_2.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0);
case IMPL_M_20 -> array -> IMPL_M_2.powerSort(array,NaturalOrder.INSTANCE);
case IMPL_M_30 -> array -> IMPL_M_3.powerSort(array,NaturalOrder.INSTANCE);
case IMPL_M_40 -> array -> IMPL_M_4.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0);
case FASTER_FINN_SORT -> array -> FasterFinnSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0);
case ASORT -> array -> ASort.sort(array, NaturalOrder.INSTANCE);
};

View File

@ -1,6 +1,6 @@
package de.uni_marburg.powersort.MSort;
import static de.uni_marburg.powersort.MSort.IMPL_M_1.*;
import static de.uni_marburg.powersort.MSort.IMPL_M_3.*;
import java.util.ArrayList;
import java.util.Arrays;
@ -13,8 +13,8 @@ public class PowerSortT {
public static void main(String[] args) {
testFillWithAscRunsHighToLow();
testMerge();
testMergeInplace();
//testMerge();
// testMergeInplace();
testExtendRun();
testPower();
testPowerFast();
@ -32,25 +32,25 @@ public class PowerSortT {
}
// Test for merge
public static void testMerge() {
Integer[] run1 ={1,4,6};
Integer []run2 = {2, 3, 5};
Integer[] result = merge(run1, run2, NaturalOrder.INSTANCE);
System.out.println("Test merge: " + result);
}
// public static void testMerge() {
// Integer[] run1 ={1,4,6};
// Integer []run2 = {2, 3, 5};
// Integer[] result = merge(run1, run2, NaturalOrder.INSTANCE);
// System.out.println("Test merge: " + result);
// }
// Test for mergeInplace
public static void testMergeInplace() {
Integer[] A = {1,4,6,2,3,5};
mergeInplace(A, 0, 3, 6,NaturalOrder.INSTANCE);
System.out.println("Test mergeInplace: " + A);
}
// public static void testMergeInplace() {
// Integer[] A = {1,4,6,2,3,5};
// mergeInplace(A, 0, 3, 6,NaturalOrder.INSTANCE);
// System.out.println("Test mergeInplace: " + A);
// }
// Test for extendRun
public static void testExtendRun() {
Integer [] A = {1, 2, 3, 6, 5, 4};
int endIndex = extendRun(A, 0,NaturalOrder.INSTANCE);
System.out.println("Test extendRun (from 0): " + endIndex);
// int endIndex = extendRun(A, 0,NaturalOrder.INSTANCE);
// System.out.println("Test extendRun (from 0): " + endIndex);
System.out.println("Modified List: " + A);
}
@ -59,8 +59,8 @@ public class PowerSortT {
int[] run1 = {0, 3};
int[] run2 = {3, 3};
int n = 6;
int powerValue = power(run1, run2, n);
System.out.println("Test power: " + powerValue);
// int powerValue = power(run1, run2, n);
// System.out.println("Test power: " + powerValue);
}
// Test for powerFast
@ -68,8 +68,8 @@ public class PowerSortT {
int[] run1 = {0, 3};
int[] run2 = {3, 3};
int n = 6;
int powerFastValue = powerFast(run1, run2, n);
System.out.println("Test powerFast: " + powerFastValue);
// int powerFastValue = powerFast(run1, run2, n);
// System.out.println("Test powerFast: " + powerFastValue);
}
// Test for mergeTopmost2
@ -78,7 +78,7 @@ public class PowerSortT {
List<int[]> runs = new ArrayList<>();
runs.add(new int[]{0, 3, 1});
runs.add(new int[]{3, 3, 1});
mergeTopmost2(A, runs,NaturalOrder.INSTANCE);
// mergeTopmost2(A, runs,NaturalOrder.INSTANCE);
System.out.println("Test mergeTopmost2: " + A);
}

View File

@ -9,9 +9,9 @@ import java.util.stream.IntStream;
import de.uni_marburg.powersort.benchmark.NaturalOrder;
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.fillWithAscRunsHighToLow;
import static de.uni_marburg.powersort.MSort.IMPL_M_1.powerSort;
//import static de.uni_marburg.powersort.MSort.IMPL_M_3.MERGE_COST;
import static de.uni_marburg.powersort.MSort.IMPL_M_3.fillWithAscRunsHighToLow;
import static de.uni_marburg.powersort.MSort.IMPL_M_3.powerSort;
class PowerSortTest {
@Test
@ -28,11 +28,11 @@ class PowerSortTest {
System.out.println();
fillWithAscRunsHighToLow(a, runs, 1);
MERGE_COST = 0;
//MERGE_COST = 0;
System.out.println("Sorting with Powersort:");
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