snippetjavaMinor
Natural merge sort in Java - follow-up 3
Viewed 0 times
mergejavafollownaturalsort
Problem
(See the previous iteration.)
Now I have optimized my natural merge sort: Suppose the input sequence is
$$\langle 2, 1, 4, 3, 6, 5, \dots, n, n - 1 \rangle.$$
My previous iterations would degrade to \$\Theta(n \log n)\$ on this input. This version will not: After reversing the second run (\$\langle 4, 3 \rangle\$), the algorithm will notice that the first element of the second run is no less than the last element of the first run, and so, it will "merge" these in constant time simply by extending the first run descriptor from \$2\$ to \$4\$, and so on.
Code:
CoderoddeArrays.java:
```
package net.coderodde.util;
import java.util.Arrays;
import java.util.Comparator;
/**
* This class contains static methods implementing a natural merge sort
* algorithm, which runs in time O(n log m), where n is the
* length of the range to sort and m is the amount of ascending or
* strictly descending contiguous subsequences usually called 'runs' in the
* input range. The algorithm is stable and the space complexity is
* O(n).
*
* @author Rodion Efremov
* @version 1.61 (Dec 13, 2015)
*/
public class CoderoddeArrays {
/**
* Sorts the entire input array.
*
* @param the array component type.
* @param array the array to sort.
* @param comparator the value comparator.
*/
public static final void sort(T[] array,
Comparator comparator) {
sort(array, 0, array.length, comparator);
}
/**
* Sorts a specific range in the input array.
*
* @param the array component type.
* @param array the array holding the requested range.
* @param fromIndex the least inclusive component index.
* @param toIndex the index one past the last inclusive component.
* @param comparator the value comparator.
*/
public static final void sort(T[] array,
int fromIndex,
Now I have optimized my natural merge sort: Suppose the input sequence is
$$\langle 2, 1, 4, 3, 6, 5, \dots, n, n - 1 \rangle.$$
My previous iterations would degrade to \$\Theta(n \log n)\$ on this input. This version will not: After reversing the second run (\$\langle 4, 3 \rangle\$), the algorithm will notice that the first element of the second run is no less than the last element of the first run, and so, it will "merge" these in constant time simply by extending the first run descriptor from \$2\$ to \$4\$, and so on.
Code:
CoderoddeArrays.java:
```
package net.coderodde.util;
import java.util.Arrays;
import java.util.Comparator;
/**
* This class contains static methods implementing a natural merge sort
* algorithm, which runs in time O(n log m), where n is the
* length of the range to sort and m is the amount of ascending or
* strictly descending contiguous subsequences usually called 'runs' in the
* input range. The algorithm is stable and the space complexity is
* O(n).
*
* @author Rodion Efremov
* @version 1.61 (Dec 13, 2015)
*/
public class CoderoddeArrays {
/**
* Sorts the entire input array.
*
* @param the array component type.
* @param array the array to sort.
* @param comparator the value comparator.
*/
public static final void sort(T[] array,
Comparator comparator) {
sort(array, 0, array.length, comparator);
}
/**
* Sorts a specific range in the input array.
*
* @param the array component type.
* @param array the array holding the requested range.
* @param fromIndex the least inclusive component index.
* @param toIndex the index one past the last inclusive component.
* @param comparator the value comparator.
*/
public static final void sort(T[] array,
int fromIndex,
Solution
if (previousRunWasDescending) {
if (comparator.compare(array[head - 1], array[head]) <= 0) {
// Merge the current run with the previous one.
queue.addToLast(runLength);
} else {
queue.enqueue(runLength);
}
} else {
queue.enqueue(runLength);
}This section of code is duplicated. I think you could extract it into a separate function, as well as merging the two conditions:
if (previousRunWasDescending && comparator.compare(array[head - 1], array[head]) <= 0) {
// Merge the current run with the previous one.
queue.addToLast(runLength);
} else {
queue.enqueue(runLength);
}Code Snippets
if (previousRunWasDescending) {
if (comparator.compare(array[head - 1], array[head]) <= 0) {
// Merge the current run with the previous one.
queue.addToLast(runLength);
} else {
queue.enqueue(runLength);
}
} else {
queue.enqueue(runLength);
}if (previousRunWasDescending && comparator.compare(array[head - 1], array[head]) <= 0) {
// Merge the current run with the previous one.
queue.addToLast(runLength);
} else {
queue.enqueue(runLength);
}Context
StackExchange Code Review Q#113821, answer score: 3
Revisions (0)
No revisions yet.