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 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};
int[] output = timsort.insertionsort(array);
System.out.println("Insertionsort test: " + Arrays.toString(output));
System.out.println("End result: " + Arrays.toString(timsort.timsort(array)));
long startTime = System.nanoTime();
int[] test = timsort.timsort(new int[]{20, 1, 573, 34, 281, 201, 0});
long endTime = System.nanoTime();
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;
public class timsort {
public static int[] insertionsort(int[] unsorted) {
private static int[] insertionsort(int[] unsorted) {
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) {
int foundIndex = binarySearch(output, unsorted[i], 0, i);
for(int j = i; j > foundIndex; --j) {
int foundIndex = binarySearch(output, unsorted[i], 0, i); // searches the right index using binary search
for(int j = i; j > foundIndex; --j) { // shift each element after the found index one to the right
output[j] = output[j - 1];
}
output[foundIndex] = unsorted[i];
output[foundIndex] = unsorted[i]; // insert the element
}
return output;
}
private static int binarySearch(int[] array, int search, int minIndex, int maxIndex) {
for(int j = maxIndex - 1; minIndex != maxIndex; j = minIndex + (maxIndex - minIndex) / 2) {
if(search >= array[j]) {
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]) {// check if the element is larger and set min or max Index accordingly
minIndex = j + 1;
}
else {
@ -28,6 +28,7 @@ public class timsort {
return minIndex;
}
public static int[] timsort(int[] unsorted) {
// calculate minrun
int r = 0;
// r becomes 1 any 1 bits are shifted off
int n = unsorted.length;
@ -36,12 +37,14 @@ public class timsort {
n >>= 1;
}
int minRun = n + r;
// split array into runs
ArrayList<int[]> runs = new ArrayList<int[]>();
for(int i = 0; i < unsorted.length - 1;) {
int j = i;
boolean ascending = 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;
for(; i < unsorted.length - 1 && (ascending || descending); ++i) {
ascendingCache = ascending;
@ -49,11 +52,11 @@ public class timsort {
ascending = ascending && unsorted[i] <= unsorted[i + 1];
descending = descending && unsorted[i] >= unsorted[i + 1];
}
if(i - j < minRun) i = j + minRun;
boolean minRunNotMet = i >= unsorted.length - 1;
if(minRunNotMet) i = unsorted.length;
int[] temp1 = Arrays.copyOfRange(unsorted, j, i);
if(!ascendingCache && descendingCache && !minRunNotMet) {
boolean minRunNotMet = i - j < minRun;
if(minRunNotMet) i = j + minRun; // if minrun is not met enlarge the array range
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); // the index same as the length is not out of Bounds because copyOfRange is excluding the last index
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
int l, temp;
for(l = 0; l < temp1.length / 2; l++) {
@ -64,43 +67,45 @@ public class timsort {
}
runs.add(temp1);
}
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));
}
return merge(notMerged)[0];
}
private static int[][] merge(int[][] notMerged) {
int notEvenLen = notMerged.length % 2;
int[][] merged = new int[notMerged.length / 2 + notEvenLen][];
for(int i = 0; i < notMerged.length - 1; i += 2) {
int[] temp = new int[notMerged[i].length + notMerged[i + 1].length];
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; /* -1 becasue index of i + 1 is used later */ i += 2) {
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;
int[] j = new int[2];
int w = 0;
int[] j = new int[2]; // index variable: [0]: notMerged[i], [1]: notMerged[i + 1]
int relativeIndexOfSmallerArray = 0;
int l = 0;
for(int gallopingCounter = 0; j[w] < notMerged[i + w].length; ++l) {
if(gallopingCounter == 7) {
int b = w != 0 ? 0 : 1;
int found = binarySearch(notMerged[i + w], notMerged[i + b][j[b]], j[w], notMerged[i + w].length - 1);
for(; j[w] < found; ++j[w], ++l) {
temp[l] = notMerged[i + w][j[w]];
for(int gallopingCounter = 0; j[relativeIndexOfSmallerArray] < notMerged[i + relativeIndexOfSmallerArray].length; ++l) {
if(gallopingCounter == 7) { // do galloping if 7 elements in a row came from one array
int relativeIndexOfLargerArray = relativeIndexOfSmallerArray != 0 ? 0 : 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[relativeIndexOfSmallerArray] < found; ++j[relativeIndexOfSmallerArray], ++l) { // copy elements
temp[l] = notMerged[i + relativeIndexOfSmallerArray][j[relativeIndexOfSmallerArray]];
}
}
int lastW = w;
w = notMerged[i][j[0]] > notMerged[i + 1][j[1]] ? 1 : 0;
temp[l] = notMerged[i + w][j[w]];
++j[w];
if(w == lastW) ++gallopingCounter;
int lastRelativeIndexOfSmallerArray = relativeIndexOfSmallerArray;
relativeIndexOfSmallerArray = notMerged[i][j[0]] > notMerged[i + 1][j[1]] ? 1 : 0;
temp[l] = notMerged[i + relativeIndexOfSmallerArray][j[relativeIndexOfSmallerArray]]; // copy the element to the output array
++j[relativeIndexOfSmallerArray];
if(relativeIndexOfSmallerArray == lastRelativeIndexOfSmallerArray ) ++gallopingCounter;
else gallopingCounter = 0;
}
int b = w != 0 ? 0 : 1;
for(int k = j[b]; l < temp.length; ++k, ++l) {
temp[l] = notMerged[i + b][k];
// after one of the not merged arrays is empty the remaining elements from the other arrays have to be copied
int relativeIndexOfLargerArray = relativeIndexOfSmallerArray != 0 ? 0 : 1;
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(merged.length == 1) return merged;
return merge(merged);
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; // sorting is finnished
return merge(merged); // do merging again
}
}