From 4268315f062d8f59554716815fffb2bf1ed58f09 Mon Sep 17 00:00:00 2001 From: finnm Date: Sun, 5 Jan 2025 14:26:07 +0100 Subject: [PATCH] Changed FasterFinnSort to use the PowerSort merge policy --- .../powersort/FinnSort/FasterFinnSort.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java index 37072ae..1f7dc8f 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java @@ -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 { +public class FasterFinnSort { /** * 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 { 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 { len < 119151 ? 24 : 49); runBase = new int[stackLen]; runLen = new int[stackLen]; + runPower = new int[stackLen]; } /* @@ -209,7 +213,7 @@ class FasterFinnSort { * @param workLen usable size of work array * @since 1.8 */ - static void sort(T[] a, int lo, int hi, Comparator c, + public static void sort(T[] a, int lo, int hi, Comparator 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 { } // 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 { * @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 { 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: