This commit is contained in:
2021-01-02 17:39:22 +01:00
parent 281c23c8d4
commit a26c4fc460
2 changed files with 48 additions and 40 deletions

View File

@ -6,9 +6,12 @@ import de.redstoneunion.git.MrGeorgen.timsort.timsort;
public class test { public class test {
public static void main(String[] args) { public static void main(String[] args) {
int[] array = {0, 3, 4, 8, -6, -6, 10, 10, 789, 456, 0, -1, -2, 8, 10, 1, 100, -100, 700, 800, 5}; long startTime = System.nanoTime();
int[] output = timsort.insertionsort(array); int[] test = timsort.timsort(new int[]{20, 1, 573, 34, 281, 201, 0});
System.out.println("Insertionsort test: " + Arrays.toString(output)); long endTime = System.nanoTime();
System.out.println("End result: " + Arrays.toString(timsort.timsort(array)));
System.out.println(Arrays.toString(test));
long duration = (endTime - startTime);
System.out.println("Program executed in " + duration + " nanoseconds.");
} }
} }

View File

@ -4,21 +4,21 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
public class timsort { public class timsort {
public static int[] insertionsort(int[] unsorted) { private static int[] insertionsort(int[] unsorted) {
int[] output = new int[unsorted.length]; int[] output = new int[unsorted.length];
output[0] = unsorted[0]; output[0] = unsorted[0]; // copies the first element
for(int i = 1; i < unsorted.length; ++i) { for(int i = 1; i < unsorted.length; ++i) {
int foundIndex = binarySearch(output, unsorted[i], 0, i); int foundIndex = binarySearch(output, unsorted[i], 0, i); // searches the right index using binary search
for(int j = i; j > foundIndex; --j) { for(int j = i; j > foundIndex; --j) { // shift each element after the found index one to the right
output[j] = output[j - 1]; output[j] = output[j - 1];
} }
output[foundIndex] = unsorted[i]; output[foundIndex] = unsorted[i]; // insert the element
} }
return output; return output;
} }
private static int binarySearch(int[] array, int search, int minIndex, int maxIndex) { private static int binarySearch(int[] array, int search, int minIndex, int maxIndex) {
for(int j = maxIndex - 1; minIndex != maxIndex; j = minIndex + (maxIndex - minIndex) / 2) { for(int j = maxIndex - 1; minIndex != maxIndex; j = minIndex + (maxIndex - minIndex) / 2 /* set j to middle between min and max Index */) {
if(search >= array[j]) { if(search >= array[j]) {// check if the element is larger and set min or max Index accordingly
minIndex = j + 1; minIndex = j + 1;
} }
else { else {
@ -28,6 +28,7 @@ public class timsort {
return minIndex; return minIndex;
} }
public static int[] timsort(int[] unsorted) { public static int[] timsort(int[] unsorted) {
// calculate minrun
int r = 0; int r = 0;
// r becomes 1 any 1 bits are shifted off // r becomes 1 any 1 bits are shifted off
int n = unsorted.length; int n = unsorted.length;
@ -36,12 +37,14 @@ public class timsort {
n >>= 1; n >>= 1;
} }
int minRun = n + r; int minRun = n + r;
// split array into runs
ArrayList<int[]> runs = new ArrayList<int[]>(); ArrayList<int[]> runs = new ArrayList<int[]>();
for(int i = 0; i < unsorted.length - 1;) { for(int i = 0; i < unsorted.length - 1;) {
int j = i; int j = i;
boolean ascending = true; boolean ascending = true;
boolean descending = true; boolean descending = true;
boolean ascendingCache = false; boolean ascendingCache = false; // cache variables are needed to know if it is ascending or descending, both ascending and descending are false after the loop
boolean descendingCache = false; boolean descendingCache = false;
for(; i < unsorted.length - 1 && (ascending || descending); ++i) { for(; i < unsorted.length - 1 && (ascending || descending); ++i) {
ascendingCache = ascending; ascendingCache = ascending;
@ -49,11 +52,11 @@ public class timsort {
ascending = ascending && unsorted[i] <= unsorted[i + 1]; ascending = ascending && unsorted[i] <= unsorted[i + 1];
descending = descending && unsorted[i] >= unsorted[i + 1]; descending = descending && unsorted[i] >= unsorted[i + 1];
} }
if(i - j < minRun) i = j + minRun; boolean minRunNotMet = i - j < minRun;
boolean minRunNotMet = i >= unsorted.length - 1; if(minRunNotMet) i = j + minRun; // if minrun is not met enlarge the array range
if(minRunNotMet) i = unsorted.length; if(i > unsorted.length) i = unsorted.length; // if the Index is out of Bounds set to the maxium.
int[] temp1 = Arrays.copyOfRange(unsorted, j, i); int[] temp1 = Arrays.copyOfRange(unsorted, j, i); // the index same as the length is not out of Bounds because copyOfRange is excluding the last index
if(!ascendingCache && descendingCache && !minRunNotMet) { if(!ascendingCache && descendingCache && !minRunNotMet) { // if the array is descending and not ascending (if it is both all values are equal) and minrun is met (if it is not met the run is not ascending nor descending because of the enlargment of the run
// reverses the array // reverses the array
int l, temp; int l, temp;
for(l = 0; l < temp1.length / 2; l++) { for(l = 0; l < temp1.length / 2; l++) {
@ -64,43 +67,45 @@ public class timsort {
} }
runs.add(temp1); runs.add(temp1);
} }
int[][] notMerged = new int[runs.size()][]; int[][] notMerged = new int[runs.size()][];
for(int i = 0; i < runs.size(); ++i) { for(int i = 0; i < runs.size(); ++i) { // sort each runs with insertionsort
notMerged[i] = insertionsort(runs.get(i)); notMerged[i] = insertionsort(runs.get(i));
} }
return merge(notMerged)[0]; return merge(notMerged)[0];
} }
private static int[][] merge(int[][] notMerged) { private static int[][] merge(int[][] notMerged) {
int notEvenLen = notMerged.length % 2; int notEvenLen = notMerged.length % 2;
int[][] merged = new int[notMerged.length / 2 + notEvenLen][]; int[][] merged = new int[notMerged.length / 2 + notEvenLen][]; // the merged array is half as the unmerged. if the length of notMerged is not even we have to add one because the one remaining arary will just be copied
for(int i = 0; i < notMerged.length - 1; i += 2) { for(int i = 0; i < notMerged.length - 1; /* -1 becasue index of i + 1 is used later */ i += 2) {
int[] temp = new int[notMerged[i].length + notMerged[i + 1].length]; int[] temp = new int[notMerged[i].length + notMerged[i + 1].length]; // length of the merged is the sum of the 2 not merged arrays
merged[i / 2] = temp; merged[i / 2] = temp;
int[] j = new int[2]; int[] j = new int[2]; // index variable: [0]: notMerged[i], [1]: notMerged[i + 1]
int w = 0; int relativeIndexOfSmallerArray = 0;
int l = 0; int l = 0;
for(int gallopingCounter = 0; j[w] < notMerged[i + w].length; ++l) { for(int gallopingCounter = 0; j[relativeIndexOfSmallerArray] < notMerged[i + relativeIndexOfSmallerArray].length; ++l) {
if(gallopingCounter == 7) { if(gallopingCounter == 7) { // do galloping if 7 elements in a row came from one array
int b = w != 0 ? 0 : 1; int relativeIndexOfLargerArray = relativeIndexOfSmallerArray != 0 ? 0 : 1;
int found = binarySearch(notMerged[i + w], notMerged[i + b][j[b]], j[w], notMerged[i + w].length - 1); int found = binarySearch(notMerged[i + relativeIndexOfSmallerArray], notMerged[i + relativeIndexOfLargerArray][j[relativeIndexOfLargerArray]], j[relativeIndexOfSmallerArray], notMerged[i + relativeIndexOfSmallerArray].length - 1); // use binray search to out how many elements can be copied from the same array
for(; j[w] < found; ++j[w], ++l) { for(; j[relativeIndexOfSmallerArray] < found; ++j[relativeIndexOfSmallerArray], ++l) { // copy elements
temp[l] = notMerged[i + w][j[w]]; temp[l] = notMerged[i + relativeIndexOfSmallerArray][j[relativeIndexOfSmallerArray]];
} }
} }
int lastW = w; int lastRelativeIndexOfSmallerArray = relativeIndexOfSmallerArray;
w = notMerged[i][j[0]] > notMerged[i + 1][j[1]] ? 1 : 0; relativeIndexOfSmallerArray = notMerged[i][j[0]] > notMerged[i + 1][j[1]] ? 1 : 0;
temp[l] = notMerged[i + w][j[w]]; temp[l] = notMerged[i + relativeIndexOfSmallerArray][j[relativeIndexOfSmallerArray]]; // copy the element to the output array
++j[w]; ++j[relativeIndexOfSmallerArray];
if(w == lastW) ++gallopingCounter; if(relativeIndexOfSmallerArray == lastRelativeIndexOfSmallerArray ) ++gallopingCounter;
else gallopingCounter = 0; else gallopingCounter = 0;
} }
int b = w != 0 ? 0 : 1; // after one of the not merged arrays is empty the remaining elements from the other arrays have to be copied
for(int k = j[b]; l < temp.length; ++k, ++l) { int relativeIndexOfLargerArray = relativeIndexOfSmallerArray != 0 ? 0 : 1;
temp[l] = notMerged[i + b][k]; for(int k = j[relativeIndexOfLargerArray]; l < temp.length; ++k, ++l) {
temp[l] = notMerged[i + relativeIndexOfLargerArray][k];
} }
} }
if(notEvenLen == 1) merged[merged.length - 1] = notMerged[notMerged.length - 1]; if(notEvenLen == 1) merged[merged.length - 1] = notMerged[notMerged.length - 1]; // copy the last array if input array length is uneven so array could not be merged
if(merged.length == 1) return merged; if(merged.length == 1) return merged; // sorting is finnished
return merge(merged); return merge(merged); // do merging again
} }
} }