refactor: IntrospectiveSort
(#5316)
This commit is contained in:
parent
66bfaff807
commit
2837585705
@ -9,76 +9,131 @@ public class IntrospectiveSort implements SortAlgorithm {
|
|||||||
|
|
||||||
private static final int INSERTION_SORT_THRESHOLD = 16;
|
private static final int INSERTION_SORT_THRESHOLD = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the given array using Introspective Sort, which combines quicksort, heapsort, and insertion sort.
|
||||||
|
*
|
||||||
|
* @param array The array to be sorted
|
||||||
|
* @param <T> The type of elements in the array, which must be comparable
|
||||||
|
* @return The sorted array
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T extends Comparable<T>> T[] sort(T[] a) {
|
public <T extends Comparable<T>> T[] sort(T[] array) {
|
||||||
int n = a.length;
|
if (array == null || array.length <= 1) {
|
||||||
introSort(a, 0, n - 1, 2 * (int) (Math.log(n) / Math.log(2)));
|
return array;
|
||||||
return a;
|
}
|
||||||
|
final int depth = 2 * (int) (Math.log(array.length) / Math.log(2));
|
||||||
|
introspectiveSort(array, 0, array.length - 1, depth);
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> void introSort(T[] a, int low, int high, int depth) {
|
/**
|
||||||
|
* Performs introspective sort on the specified subarray.
|
||||||
|
*
|
||||||
|
* @param array The array to be sorted
|
||||||
|
* @param low The starting index of the subarray
|
||||||
|
* @param high The ending index of the subarray
|
||||||
|
* @param depth The current depth of recursion
|
||||||
|
* @param <T> The type of elements in the array, which must be comparable
|
||||||
|
*/
|
||||||
|
private static <T extends Comparable<T>> void introspectiveSort(T[] array, final int low, int high, final int depth) {
|
||||||
while (high - low > INSERTION_SORT_THRESHOLD) {
|
while (high - low > INSERTION_SORT_THRESHOLD) {
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
heapSort(a, low, high);
|
heapSort(array, low, high);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int pivotIndex = partition(a, low, high);
|
final int pivotIndex = partition(array, low, high);
|
||||||
introSort(a, pivotIndex + 1, high, depth - 1);
|
introspectiveSort(array, pivotIndex + 1, high, depth - 1);
|
||||||
high = pivotIndex - 1;
|
high = pivotIndex - 1;
|
||||||
}
|
}
|
||||||
insertionSort(a, low, high);
|
insertionSort(array, low, high);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> int partition(T[] a, int low, int high) {
|
/**
|
||||||
int pivotIndex = low + (int) (Math.random() * (high - low + 1));
|
* Partitions the array around a pivot.
|
||||||
SortUtils.swap(a, pivotIndex, high);
|
*
|
||||||
T pivot = a[high];
|
* @param array The array to be partitioned
|
||||||
|
* @param low The starting index of the subarray
|
||||||
|
* @param high The ending index of the subarray
|
||||||
|
* @param <T> The type of elements in the array, which must be comparable
|
||||||
|
* @return The index of the pivot
|
||||||
|
*/
|
||||||
|
private static <T extends Comparable<T>> int partition(T[] array, final int low, final int high) {
|
||||||
|
final int pivotIndex = low + (int) (Math.random() * (high - low + 1));
|
||||||
|
SortUtils.swap(array, pivotIndex, high);
|
||||||
|
final T pivot = array[high];
|
||||||
int i = low - 1;
|
int i = low - 1;
|
||||||
for (int j = low; j <= high - 1; j++) {
|
for (int j = low; j < high; j++) {
|
||||||
if (a[j].compareTo(pivot) <= 0) {
|
if (array[j].compareTo(pivot) <= 0) {
|
||||||
i++;
|
i++;
|
||||||
SortUtils.swap(a, i, j);
|
SortUtils.swap(array, i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SortUtils.swap(a, i + 1, high);
|
SortUtils.swap(array, i + 1, high);
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> void insertionSort(T[] a, int low, int high) {
|
/**
|
||||||
|
* Sorts a subarray using insertion sort.
|
||||||
|
*
|
||||||
|
* @param array The array to be sorted
|
||||||
|
* @param low The starting index of the subarray
|
||||||
|
* @param high The ending index of the subarray
|
||||||
|
* @param <T> The type of elements in the array, which must be comparable
|
||||||
|
*/
|
||||||
|
private static <T extends Comparable<T>> void insertionSort(T[] array, final int low, final int high) {
|
||||||
for (int i = low + 1; i <= high; i++) {
|
for (int i = low + 1; i <= high; i++) {
|
||||||
T key = a[i];
|
final T key = array[i];
|
||||||
int j = i - 1;
|
int j = i - 1;
|
||||||
while (j >= low && a[j].compareTo(key) > 0) {
|
while (j >= low && array[j].compareTo(key) > 0) {
|
||||||
a[j + 1] = a[j];
|
array[j + 1] = array[j];
|
||||||
j--;
|
j--;
|
||||||
}
|
}
|
||||||
a[j + 1] = key;
|
array[j + 1] = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> void heapSort(T[] a, int low, int high) {
|
/**
|
||||||
for (int i = (high + low - 1) / 2; i >= low; i--) {
|
* Sorts a subarray using heapsort.
|
||||||
heapify(a, i, high - low + 1, low);
|
*
|
||||||
|
* @param array The array to be sorted
|
||||||
|
* @param low The starting index of the subarray
|
||||||
|
* @param high The ending index of the subarray
|
||||||
|
* @param <T> The type of elements in the array, which must be comparable
|
||||||
|
*/
|
||||||
|
private static <T extends Comparable<T>> void heapSort(T[] array, final int low, final int high) {
|
||||||
|
final int n = high - low + 1;
|
||||||
|
for (int i = (n / 2) - 1; i >= 0; i--) {
|
||||||
|
heapify(array, i, n, low);
|
||||||
}
|
}
|
||||||
for (int i = high; i > low; i--) {
|
for (int i = high; i > low; i--) {
|
||||||
SortUtils.swap(a, low, i);
|
SortUtils.swap(array, low, i);
|
||||||
heapify(a, low, i - low, low);
|
heapify(array, 0, i - low, low);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> void heapify(T[] a, int i, int n, int low) {
|
/**
|
||||||
int left = 2 * i - low + 1;
|
* Maintains the heap property for a subarray.
|
||||||
int right = 2 * i - low + 2;
|
*
|
||||||
|
* @param array The array to be heapified
|
||||||
|
* @param i The index to be heapified
|
||||||
|
* @param n The size of the heap
|
||||||
|
* @param low The starting index of the subarray
|
||||||
|
* @param <T> The type of elements in the array, which must be comparable
|
||||||
|
*/
|
||||||
|
private static <T extends Comparable<T>> void heapify(T[] array, final int i, final int n, final int low) {
|
||||||
|
final int left = 2 * i + 1;
|
||||||
|
final int right = 2 * i + 2;
|
||||||
int largest = i;
|
int largest = i;
|
||||||
if (left < n && a[left].compareTo(a[largest]) > 0) {
|
|
||||||
|
if (left < n && array[low + left].compareTo(array[low + largest]) > 0) {
|
||||||
largest = left;
|
largest = left;
|
||||||
}
|
}
|
||||||
if (right < n && a[right].compareTo(a[largest]) > 0) {
|
if (right < n && array[low + right].compareTo(array[low + largest]) > 0) {
|
||||||
largest = right;
|
largest = right;
|
||||||
}
|
}
|
||||||
if (largest != i) {
|
if (largest != i) {
|
||||||
SortUtils.swap(a, i, largest);
|
SortUtils.swap(array, low + i, low + largest);
|
||||||
heapify(a, largest, n, low);
|
heapify(array, largest, n, low);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,8 @@
|
|||||||
package com.thealgorithms.sorts;
|
package com.thealgorithms.sorts;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
public class IntrospectiveSortTest extends SortingAlgorithmTest {
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
@Override
|
||||||
|
SortAlgorithm getSortAlgorithm() {
|
||||||
import org.junit.jupiter.api.Test;
|
return new IntrospectiveSort();
|
||||||
|
|
||||||
public class IntrospectiveSortTest {
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void strandSortNonDuplicateTest() {
|
|
||||||
Integer[] expectedArray = {1, 2, 3, 4, 5};
|
|
||||||
Integer[] actualList = new IntrospectiveSort().sort(expectedArray);
|
|
||||||
assertArrayEquals(expectedArray, actualList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void strandSortDuplicateTest() {
|
|
||||||
Integer[] expectedArray = {2, 2, 2, 5, 7};
|
|
||||||
Integer[] actualList = new IntrospectiveSort().sort(expectedArray);
|
|
||||||
assertArrayEquals(expectedArray, actualList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void strandSortEmptyTest() {
|
|
||||||
Integer[] expectedArray = {};
|
|
||||||
Integer[] actualList = new IntrospectiveSort().sort(expectedArray);
|
|
||||||
assertArrayEquals(expectedArray, actualList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void strandSortNullTest() {
|
|
||||||
Integer[] expectedArray = null;
|
|
||||||
assertThrows(NullPointerException.class, () -> { new IntrospectiveSort().sort(expectedArray); });
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void strandSortNegativeTest() {
|
|
||||||
Integer[] expectedArray = {-1, -2, -3, -4, -5};
|
|
||||||
Integer[] actualList = new IntrospectiveSort().sort(expectedArray);
|
|
||||||
assertArrayEquals(expectedArray, actualList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void strandSortNegativeAndPositiveTest() {
|
|
||||||
Integer[] expectedArray = {-1, -2, -3, 4, 5};
|
|
||||||
Integer[] actualList = new IntrospectiveSort().sort(expectedArray);
|
|
||||||
assertArrayEquals(expectedArray, actualList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
// valid test case
|
|
||||||
public void allSameTest() {
|
|
||||||
Integer[] expectedArray = {1, 1, 1, 1, 1};
|
|
||||||
Integer[] actualList = new IntrospectiveSort().sort(expectedArray);
|
|
||||||
assertArrayEquals(expectedArray, actualList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user