Skip to content

refactor: IntrospectiveSort #5316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 89 additions & 34 deletions src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,76 +9,131 @@ public class IntrospectiveSort implements SortAlgorithm {

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
public <T extends Comparable<T>> T[] sort(T[] a) {
int n = a.length;
introSort(a, 0, n - 1, 2 * (int) (Math.log(n) / Math.log(2)));
return a;
public <T extends Comparable<T>> T[] sort(T[] array) {
if (array == null || array.length <= 1) {
return array;
}
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) {
if (depth == 0) {
heapSort(a, low, high);
heapSort(array, low, high);
return;
}
int pivotIndex = partition(a, low, high);
introSort(a, pivotIndex + 1, high, depth - 1);
final int pivotIndex = partition(array, low, high);
introspectiveSort(array, pivotIndex + 1, high, depth - 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));
SortUtils.swap(a, pivotIndex, high);
T pivot = a[high];
/**
* Partitions the array around a pivot.
*
* @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;
for (int j = low; j <= high - 1; j++) {
if (a[j].compareTo(pivot) <= 0) {
for (int j = low; j < high; j++) {
if (array[j].compareTo(pivot) <= 0) {
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;
}

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++) {
T key = a[i];
final T key = array[i];
int j = i - 1;
while (j >= low && a[j].compareTo(key) > 0) {
a[j + 1] = a[j];
while (j >= low && array[j].compareTo(key) > 0) {
array[j + 1] = array[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--) {
heapify(a, i, high - low + 1, low);
/**
* Sorts a subarray using heapsort.
*
* @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--) {
SortUtils.swap(a, low, i);
heapify(a, low, i - low, low);
SortUtils.swap(array, low, i);
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;
int right = 2 * i - low + 2;
/**
* Maintains the heap property for a subarray.
*
* @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;
if (left < n && a[left].compareTo(a[largest]) > 0) {

if (left < n && array[low + left].compareTo(array[low + largest]) > 0) {
largest = left;
}
if (right < n && a[right].compareTo(a[largest]) > 0) {
if (right < n && array[low + right].compareTo(array[low + largest]) > 0) {
largest = right;
}
if (largest != i) {
SortUtils.swap(a, i, largest);
heapify(a, largest, n, low);
SortUtils.swap(array, low + i, low + largest);
heapify(array, largest, n, low);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,63 +1,8 @@
package com.thealgorithms.sorts;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.Test;

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);
public class IntrospectiveSortTest extends SortingAlgorithmTest {
@Override
SortAlgorithm getSortAlgorithm() {
return new IntrospectiveSort();
}
}