From 2837585705523db0d08cb03c70fc89985855729f Mon Sep 17 00:00:00 2001 From: Alex Klymenko Date: Sun, 11 Aug 2024 20:00:47 +0200 Subject: [PATCH] refactor: `IntrospectiveSort` (#5316) --- .../sorts/IntrospectiveSort.java | 123 +++++++++++++----- .../sorts/IntrospectiveSortTest.java | 63 +-------- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java b/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java index 32d942dc..12ef197b 100644 --- a/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java +++ b/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java @@ -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 The type of elements in the array, which must be comparable + * @return The sorted array + */ @Override - public > 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[] 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 > 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 The type of elements in the array, which must be comparable + */ + private static > 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 > 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 The type of elements in the array, which must be comparable + * @return The index of the pivot + */ + private static > 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 > 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 The type of elements in the array, which must be comparable + */ + private static > 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 > 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 The type of elements in the array, which must be comparable + */ + private static > 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 > 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 The type of elements in the array, which must be comparable + */ + private static > 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); } } } diff --git a/src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java b/src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java index a5c6905f..7760ee38 100644 --- a/src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java @@ -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(); } }