From 6a2d14e11f3d49459accaae3c24750c50b015404 Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Tue, 14 Oct 2025 15:58:08 +0530 Subject: [PATCH 1/9] Added Smoothsort algorithm with tests [Sorts] --- .../com/thealgorithms/sorts/SmoothSort.java | 136 ++++++++++++++++++ .../thealgorithms/sorts/SmoothSortTest.java | 82 +++++++++++ 2 files changed, 218 insertions(+) create mode 100644 src/main/java/com/thealgorithms/sorts/SmoothSort.java create mode 100644 src/test/java/com/thealgorithms/sorts/SmoothSortTest.java diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java new file mode 100644 index 000000000000..7161cd6298e0 --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -0,0 +1,136 @@ +package com.thealgorithms.sorts; + +/** + * Implements the SmoothSort algorithm created by Edsger W. Dijkstra. + * + *

SmoothSort is an adaptive comparison sorting algorithm. It is a variation of + * heapsort that can efficiently sort arrays that are already substantially + * sorted, approaching an O(n) time complexity in the best case. Its worst-case + * time complexity is O(n log n). + * + *

The algorithm works by building a series of "Leonardo heaps", which are + * heaps that obey a specific size constraint based on Leonardo numbers. + * The list is first partitioned into this implicit sequence of heaps, and then + * the largest element is repeatedly extracted and placed in its final sorted + * position. + * + * @see Wikipedia: Smoothsort + */ +public final class SmoothSort { + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private SmoothSort() {} + + // Leonardo numbers: L(0)=1, L(1)=1, L(k+2)=L(k+1)+L(k)-1 + // We store pre-calculated Leonardo numbers up to a reasonable limit. + private static final int[] LP = { + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, + }; + + /** + * Sorts an array in ascending order using the SmoothSort algorithm. + * + * @param the type of elements in the array, which must be comparable. + * @param arr the array to be sorted. + */ + public static > void sort(T[] arr) { + if (arr == null || arr.length <= 1) { + return; + } + int n = arr.length; + + // Bitmasks representing the sizes of the Leonardo heaps. + // q: rightmost heap, r: size of the heap. + int q = 1; + int r = 0; + int p = 1; // Represents the sequence of heap sizes. + + // Build the series of Leonardo heaps. + while (q < n) { + r = q; + q = q + p + 1; + p = r; + } + + // Main sorting loop: iteratively place the largest element at the end. + while (q > 1) { + q = q - 1; + int rshift = p; + p = q - rshift; + + while (rshift > 1) { + sift(arr, p, rshift); + rshift = rshift / 2; + sift(arr, p - rshift, q - rshift + p); + } + trinkle(arr, p, q); + } + trinkle(arr, 0, 1); + } + + /** + * Helper function to restore the heap property by "sifting" the root down. + * This is used when the root of a heap is smaller than its children. + */ + private static > void sift(T[] arr, int p, int q) { + int r = q - 1; + while (r > p) { + if (arr[p].compareTo(arr[r]) < 0) { + swap(arr, p, r); + } + r--; + } + } + + /** + * Helper function to insert a new element into the heap structure. + * It "trinkles" the element up to its correct position. + */ + private static > void trinkle(T[] arr, int p, int q) { + int r = q - 1; + while (p < r) { + int maxIndex = p; + if (arr[maxIndex].compareTo(arr[r]) < 0) { + maxIndex = r; + } + + int p1 = p; + while (p1 < q) { + int child1 = p1 + 1; + int child2 = q - (p1 - p); + + if (child1 < q && arr[maxIndex].compareTo(arr[child1]) < 0) { + maxIndex = child1; + } + if (child2 < q && arr[maxIndex].compareTo(arr[child2]) < 0) { + maxIndex = child2; + } + + int nextP1 = child2; + if (child1 >= q) { + break; + } + p1 = nextP1; + } + + if (maxIndex == p) { + break; + } + + swap(arr, p, maxIndex); + p = maxIndex; + } + sift(arr, 0, p); + } + + /** + * Swaps two elements in an array. + */ + private static void swap(T[] arr, int i, int j) { + T temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java new file mode 100644 index 000000000000..d76328f08268 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java @@ -0,0 +1,82 @@ +package com.thealgorithms.sorts; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the SmoothSort class. + */ +final class SmoothSortTest { + + @Test + @DisplayName("Test with an empty array") + void testSortEmptyArray() { + Integer[] array = {}; + SmoothSort.sort(array); + assertArrayEquals(new Integer[] {}, array); + } + + @Test + @DisplayName("Test with a single-element array") + void testSortSingleElementArray() { + Integer[] array = {42}; + SmoothSort.sort(array); + assertArrayEquals(new Integer[] {42}, array); + } + + @Test + @DisplayName("Test with a simple unsorted array of integers") + void testSortSimpleIntegerArray() { + Integer[] array = {5, 8, 3, 1, 9, 4, 7, 2, 6}; + Integer[] expected = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + SmoothSort.sort(array); + assertArrayEquals(expected, array); + } + + @Test + @DisplayName("Test with an already sorted array (best case)") + void testSortAlreadySortedArray() { + Integer[] array = {10, 20, 30, 40, 50}; + Integer[] expected = {10, 20, 30, 40, 50}; + SmoothSort.sort(array); + assertArrayEquals(expected, array); + } + + @Test + @DisplayName("Test with a reverse sorted array (worst case)") + void testSortReverseSortedArray() { + Integer[] array = {55, 44, 33, 22, 11}; + Integer[] expected = {11, 22, 33, 44, 55}; + SmoothSort.sort(array); + assertArrayEquals(expected, array); + } + + @Test + @DisplayName("Test with an array containing duplicate elements") + void testSortArrayWithDuplicates() { + Integer[] array = {7, 2, 9, 2, 5, 7, 9, 1, 5}; + Integer[] expected = {1, 2, 2, 5, 5, 7, 7, 9, 9}; + SmoothSort.sort(array); + assertArrayEquals(expected, array); + } + + @Test + @DisplayName("Test with an array of strings") + void testSortStringArray() { + String[] array = {"banana", "apple", "cherry", "date", "fig"}; + String[] expected = {"apple", "banana", "cherry", "date", "fig"}; + SmoothSort.sort(array); + assertArrayEquals(expected, array); + } + + @Test + @DisplayName("Test with an array containing negative numbers") + void testSortArrayWithNegativeNumbers() { + Integer[] array = {-5, 8, -3, 0, 9, -4, 7, 2, -6}; + Integer[] expected = {-6, -5, -4, -3, 0, 2, 7, 8, 9}; + SmoothSort.sort(array); + assertArrayEquals(expected, array); + } +} \ No newline at end of file From f20ec126a9501680f28ebaf3cd18162d4637d42f Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Tue, 14 Oct 2025 16:16:39 +0530 Subject: [PATCH 2/9] style: Apply clang-format --- .../com/thealgorithms/sorts/SmoothSort.java | 49 +++++++++++++++++-- .../thealgorithms/sorts/SmoothSortTest.java | 2 +- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 7161cd6298e0..61d658cb24bb 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -21,12 +21,55 @@ public final class SmoothSort { /** * Private constructor to prevent instantiation of this utility class. */ - private SmoothSort() {} + private SmoothSort() { + } // Leonardo numbers: L(0)=1, L(1)=1, L(k+2)=L(k+1)+L(k)-1 // We store pre-calculated Leonardo numbers up to a reasonable limit. private static final int[] LP = { - 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, + 1, + 1, + 3, + 5, + 9, + 15, + 25, + 41, + 67, + 109, + 177, + 287, + 465, + 753, + 1219, + 1973, + 3193, + 5167, + 8361, + 13529, + 21891, + 35421, + 57313, + 92735, + 150049, + 242785, + 392835, + 635621, + 1028457, + 1664079, + 2692537, + 4356617, + 7049155, + 11405773, + 18454929, + 29860703, + 48315633, + 78176337, + 126491971, + 204668309, + 331160281, + 535828591, + 866988873, }; /** @@ -133,4 +176,4 @@ private static void swap(T[] arr, int i, int j) { arr[i] = arr[j]; arr[j] = temp; } -} \ No newline at end of file +} diff --git a/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java index d76328f08268..9b1c368527d0 100644 --- a/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java @@ -79,4 +79,4 @@ void testSortArrayWithNegativeNumbers() { SmoothSort.sort(array); assertArrayEquals(expected, array); } -} \ No newline at end of file +} From 0f7a36071f304392257ab1d6e4d645e7a378b7c3 Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Tue, 14 Oct 2025 23:38:31 +0530 Subject: [PATCH 3/9] fix: Correct Smoothsort logic to prevent index out of bounds errors --- .../com/thealgorithms/sorts/SmoothSort.java | 183 ++++++------------ 1 file changed, 64 insertions(+), 119 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 61d658cb24bb..4455659a532d 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -1,9 +1,9 @@ package com.thealgorithms.sorts; /** - * Implements the SmoothSort algorithm created by Edsger W. Dijkstra. + * Implements the Smoothsort algorithm created by Edsger W. Dijkstra. * - *

SmoothSort is an adaptive comparison sorting algorithm. It is a variation of + *

Smoothsort is an adaptive comparison sorting algorithm. It is a variation of * heapsort that can efficiently sort arrays that are already substantially * sorted, approaching an O(n) time complexity in the best case. Its worst-case * time complexity is O(n log n). @@ -21,59 +21,15 @@ public final class SmoothSort { /** * Private constructor to prevent instantiation of this utility class. */ - private SmoothSort() { - } + private SmoothSort() {} - // Leonardo numbers: L(0)=1, L(1)=1, L(k+2)=L(k+1)+L(k)-1 - // We store pre-calculated Leonardo numbers up to a reasonable limit. + // Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1 private static final int[] LP = { - 1, - 1, - 3, - 5, - 9, - 15, - 25, - 41, - 67, - 109, - 177, - 287, - 465, - 753, - 1219, - 1973, - 3193, - 5167, - 8361, - 13529, - 21891, - 35421, - 57313, - 92735, - 150049, - 242785, - 392835, - 635621, - 1028457, - 1664079, - 2692537, - 4356617, - 7049155, - 11405773, - 18454929, - 29860703, - 48315633, - 78176337, - 126491971, - 204668309, - 331160281, - 535828591, - 866988873, + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, }; /** - * Sorts an array in ascending order using the SmoothSort algorithm. + * Sorts an array in ascending order using the Smoothsort algorithm. * * @param the type of elements in the array, which must be comparable. * @param arr the array to be sorted. @@ -84,96 +40,85 @@ public static > void sort(T[] arr) { } int n = arr.length; - // Bitmasks representing the sizes of the Leonardo heaps. - // q: rightmost heap, r: size of the heap. - int q = 1; - int r = 0; - int p = 1; // Represents the sequence of heap sizes. - - // Build the series of Leonardo heaps. - while (q < n) { - r = q; - q = q + p + 1; - p = r; + int head = 0; // The head of the list to be sorted + long p = 1; // A bitmask representing the sizes of the heaps. + int q = 1; // Order of the rightmost heap + + // Phase 1: Build the forest of heaps + for (head = 0; head < n - 1; head++) { + if ((p & 7) == 3) { + // Heaps of order k and k-1 merge to form a heap of order k+1 + p >>>= 2; + q += 2; + } else { + p >>>= 1; + q = (Long.numberOfTrailingZeros(p) + 1); + } + p |= 1; + trinkle(arr, head, p, q); } - - // Main sorting loop: iteratively place the largest element at the end. - while (q > 1) { - q = q - 1; - int rshift = p; - p = q - rshift; - - while (rshift > 1) { - sift(arr, p, rshift); - rshift = rshift / 2; - sift(arr, p - rshift, q - rshift + p); + trinkle(arr, n - 1, p, q); + + // Phase 2: Deconstruct the forest to sort the array + for (head = n - 1; head > 0; head--) { + if (q <= 1) { + p >>>= q; + q = (Long.numberOfTrailingZeros(p) + 1); + } else { + p >>>= 1; + q--; + sift(arr, head - LP[q], q); + p |= (1L << (q - 1)); + trinkle(arr, head - 1, p, q); } - trinkle(arr, p, q); } - trinkle(arr, 0, 1); } /** - * Helper function to restore the heap property by "sifting" the root down. - * This is used when the root of a heap is smaller than its children. + * Sifts the root of a heap down to restore the heap property. */ - private static > void sift(T[] arr, int p, int q) { - int r = q - 1; - while (r > p) { - if (arr[p].compareTo(arr[r]) < 0) { - swap(arr, p, r); + private static > void sift(T[] arr, int head, int order) { + while (order >= 2) { + int rightChild = head - 1; + int leftChild = head - LP[order] + LP[order - 1]; + + if (arr[head].compareTo(arr[leftChild]) >= 0 && arr[head].compareTo(arr[rightChild]) >= 0) { + break; + } + + if (arr[leftChild].compareTo(arr[rightChild]) > 0) { + swap(arr, head, leftChild); + head = leftChild; + order -= 1; + } else { + swap(arr, head, rightChild); + head = rightChild; + order -= 2; } - r--; } } /** - * Helper function to insert a new element into the heap structure. - * It "trinkles" the element up to its correct position. + * Restores the heap property by "trinkling" an element up the chain of heaps. */ - private static > void trinkle(T[] arr, int p, int q) { - int r = q - 1; - while (p < r) { - int maxIndex = p; - if (arr[maxIndex].compareTo(arr[r]) < 0) { - maxIndex = r; - } - - int p1 = p; - while (p1 < q) { - int child1 = p1 + 1; - int child2 = q - (p1 - p); - - if (child1 < q && arr[maxIndex].compareTo(arr[child1]) < 0) { - maxIndex = child1; - } - if (child2 < q && arr[maxIndex].compareTo(arr[child2]) < 0) { - maxIndex = child2; - } - - int nextP1 = child2; - if (child1 >= q) { - break; - } - p1 = nextP1; - } - - if (maxIndex == p) { + private static > void trinkle(T[] arr, int head, long p, int q) { + while (p > 1 && (p & 2) != 0) { + int parent = head - LP[q]; + if (arr[parent].compareTo(arr[head]) >= 0) { break; } - swap(arr, p, maxIndex); - p = maxIndex; + swap(arr, head, parent); + head = parent; + p >>>= 1; + q--; } - sift(arr, 0, p); + sift(arr, head, q); } - /** - * Swaps two elements in an array. - */ private static void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } -} +} \ No newline at end of file From b98407def10c989708e6b214beaa2ae2d61da59d Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Tue, 14 Oct 2025 23:41:13 +0530 Subject: [PATCH 4/9] fix: Correct Smoothsort logic to prevent index out of bounds errors2 --- .../com/thealgorithms/sorts/SmoothSort.java | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 4455659a532d..ae3b0a0d3feb 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -21,11 +21,54 @@ public final class SmoothSort { /** * Private constructor to prevent instantiation of this utility class. */ - private SmoothSort() {} + private SmoothSort() { + } // Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1 private static final int[] LP = { - 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, + 1, + 1, + 3, + 5, + 9, + 15, + 25, + 41, + 67, + 109, + 177, + 287, + 465, + 753, + 1219, + 1973, + 3193, + 5167, + 8361, + 13529, + 21891, + 35421, + 57313, + 92735, + 150049, + 242785, + 392835, + 635621, + 1028457, + 1664079, + 2692537, + 4356617, + 7049155, + 11405773, + 18454929, + 29860703, + 48315633, + 78176337, + 126491971, + 204668309, + 331160281, + 535828591, + 866988873, }; /** @@ -121,4 +164,4 @@ private static void swap(T[] arr, int i, int j) { arr[i] = arr[j]; arr[j] = temp; } -} \ No newline at end of file +} From 85f03d167a176b7415568de2ab5261f46a68d0ae Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Tue, 14 Oct 2025 23:50:46 +0530 Subject: [PATCH 5/9] fix: Final correction for Smoothsort logic --- .../com/thealgorithms/sorts/SmoothSort.java | 146 +++++++----------- 1 file changed, 53 insertions(+), 93 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index ae3b0a0d3feb..ddafd3e5a13f 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -21,54 +21,11 @@ public final class SmoothSort { /** * Private constructor to prevent instantiation of this utility class. */ - private SmoothSort() { - } + private SmoothSort() {} // Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1 private static final int[] LP = { - 1, - 1, - 3, - 5, - 9, - 15, - 25, - 41, - 67, - 109, - 177, - 287, - 465, - 753, - 1219, - 1973, - 3193, - 5167, - 8361, - 13529, - 21891, - 35421, - 57313, - 92735, - 150049, - 242785, - 392835, - 635621, - 1028457, - 1664079, - 2692537, - 4356617, - 7049155, - 11405773, - 18454929, - 29860703, - 48315633, - 78176337, - 126491971, - 204668309, - 331160281, - 535828591, - 866988873, + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, }; /** @@ -82,81 +39,84 @@ public static > void sort(T[] arr) { return; } int n = arr.length; - int head = 0; // The head of the list to be sorted long p = 1; // A bitmask representing the sizes of the heaps. - int q = 1; // Order of the rightmost heap + int q = 1; // Size of the rightmost heap // Phase 1: Build the forest of heaps - for (head = 0; head < n - 1; head++) { - if ((p & 7) == 3) { - // Heaps of order k and k-1 merge to form a heap of order k+1 + while (head < n) { + if ((p & 3) == 3) { + // Combine the last two heaps p >>>= 2; - q += 2; - } else { + q = LP[Long.numberOfTrailingZeros(p) + 2] - 1; + } else if ((p & 1) == 1) { p >>>= 1; - q = (Long.numberOfTrailingZeros(p) + 1); + q = 1; } - p |= 1; - trinkle(arr, head, p, q); + + if (head + q < n) { + p = (p << 1) | 1; + } else { + int order = Long.numberOfTrailingZeros(p); + while (head + LP[order] >= n) { + p &= ~(1L << order); + order--; + } + } + head++; + trinkle(arr, head - 1, p); } - trinkle(arr, n - 1, p, q); // Phase 2: Deconstruct the forest to sort the array - for (head = n - 1; head > 0; head--) { - if (q <= 1) { - p >>>= q; - q = (Long.numberOfTrailingZeros(p) + 1); - } else { - p >>>= 1; - q--; - sift(arr, head - LP[q], q); - p |= (1L << (q - 1)); - trinkle(arr, head - 1, p, q); + while (head > 1) { + head--; + long orderMask = p & -p; // lowest set bit + int order = Long.numberOfTrailingZeros(orderMask); + if (order > 0) { + p &= ~orderMask; + sift(arr, head - LP[order] + 1, order - 1); } } } - /** - * Sifts the root of a heap down to restore the heap property. - */ - private static > void sift(T[] arr, int head, int order) { + private static > void sift(T[] arr, int start, int order) { + if (order < 2) { + return; + } + int root = start; while (order >= 2) { - int rightChild = head - 1; - int leftChild = head - LP[order] + LP[order - 1]; - - if (arr[head].compareTo(arr[leftChild]) >= 0 && arr[head].compareTo(arr[rightChild]) >= 0) { + int rightChild = root - 1; + int leftChild = root - LP[order] + LP[order - 1]; + if (arr[root].compareTo(arr[leftChild]) >= 0 && arr[root].compareTo(arr[rightChild]) >= 0) { break; } - if (arr[leftChild].compareTo(arr[rightChild]) > 0) { - swap(arr, head, leftChild); - head = leftChild; + swap(arr, root, leftChild); + root = leftChild; order -= 1; } else { - swap(arr, head, rightChild); - head = rightChild; + swap(arr, root, rightChild); + root = rightChild; order -= 2; } } } - /** - * Restores the heap property by "trinkling" an element up the chain of heaps. - */ - private static > void trinkle(T[] arr, int head, long p, int q) { - while (p > 1 && (p & 2) != 0) { - int parent = head - LP[q]; - if (arr[parent].compareTo(arr[head]) >= 0) { + private static > void trinkle(T[] arr, int head, long p) { + int root = head; + while (p > 1) { + int order = Long.numberOfTrailingZeros(p); + p &= ~(1L << order); + int parentOrder = Long.numberOfTrailingZeros(p); + int parent = root - LP[order]; + + if (arr[parent].compareTo(arr[root]) >= 0) { break; } - - swap(arr, head, parent); - head = parent; - p >>>= 1; - q--; + swap(arr, root, parent); + root = parent; } - sift(arr, head, q); + sift(arr, root, Long.numberOfTrailingZeros(p & -p)); } private static void swap(T[] arr, int i, int j) { @@ -164,4 +124,4 @@ private static void swap(T[] arr, int i, int j) { arr[i] = arr[j]; arr[j] = temp; } -} +} \ No newline at end of file From afe0f4d396227712b8ac80421cddeb252af76c6d Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Tue, 14 Oct 2025 23:52:25 +0530 Subject: [PATCH 6/9] fix: Final correction for Smoothsort logic --- .../com/thealgorithms/sorts/SmoothSort.java | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index ddafd3e5a13f..639ff6fdb46d 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -21,11 +21,54 @@ public final class SmoothSort { /** * Private constructor to prevent instantiation of this utility class. */ - private SmoothSort() {} + private SmoothSort() { + } // Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1 private static final int[] LP = { - 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, + 1, + 1, + 3, + 5, + 9, + 15, + 25, + 41, + 67, + 109, + 177, + 287, + 465, + 753, + 1219, + 1973, + 3193, + 5167, + 8361, + 13529, + 21891, + 35421, + 57313, + 92735, + 150049, + 242785, + 392835, + 635621, + 1028457, + 1664079, + 2692537, + 4356617, + 7049155, + 11405773, + 18454929, + 29860703, + 48315633, + 78176337, + 126491971, + 204668309, + 331160281, + 535828591, + 866988873, }; /** @@ -124,4 +167,4 @@ private static void swap(T[] arr, int i, int j) { arr[i] = arr[j]; arr[j] = temp; } -} \ No newline at end of file +} From 2f28cc2450a675c93309bada1143428156b06a12 Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Wed, 15 Oct 2025 00:01:41 +0530 Subject: [PATCH 7/9] fix: Final correction for Smoothsort logic to resolve index errors --- .../com/thealgorithms/sorts/SmoothSort.java | 84 +++++++++---------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 639ff6fdb46d..357471bd3878 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -91,75 +91,73 @@ public static > void sort(T[] arr) { if ((p & 3) == 3) { // Combine the last two heaps p >>>= 2; - q = LP[Long.numberOfTrailingZeros(p) + 2] - 1; - } else if ((p & 1) == 1) { + q += 2; + } else { p >>>= 1; q = 1; } - if (head + q < n) { - p = (p << 1) | 1; - } else { - int order = Long.numberOfTrailingZeros(p); - while (head + LP[order] >= n) { - p &= ~(1L << order); - order--; - } + p |= 1L << q; + + while (head + LP[q] > n) { + p &= ~(1L << q); + q--; } head++; - trinkle(arr, head - 1, p); + trinkle(arr, head - 1, p, q); } // Phase 2: Deconstruct the forest to sort the array - while (head > 1) { - head--; - long orderMask = p & -p; // lowest set bit - int order = Long.numberOfTrailingZeros(orderMask); - if (order > 0) { - p &= ~orderMask; - sift(arr, head - LP[order] + 1, order - 1); + for (head = n - 1; head > 0; head--) { + if (q <= 1) { + p >>>= q; + q = Long.numberOfTrailingZeros(p) + 1; + } else { + p &= ~(1L << q); + q--; + int prevHeapOrder = Long.numberOfTrailingZeros(p) + 1; + sift(arr, head - LP[q], q); + p |= (1L << (prevHeapOrder - 1)); + trinkle(arr, head - 1, p, prevHeapOrder); } } } - private static > void sift(T[] arr, int start, int order) { - if (order < 2) { - return; - } - int root = start; + private static > void sift(T[] arr, int head, int order) { while (order >= 2) { - int rightChild = root - 1; - int leftChild = root - LP[order] + LP[order - 1]; - if (arr[root].compareTo(arr[leftChild]) >= 0 && arr[root].compareTo(arr[rightChild]) >= 0) { + int rightChild = head - 1; + int leftChild = head - LP[order] + LP[order - 1]; + + if (arr[head].compareTo(arr[leftChild]) >= 0 && arr[head].compareTo(arr[rightChild]) >= 0) { break; } if (arr[leftChild].compareTo(arr[rightChild]) > 0) { - swap(arr, root, leftChild); - root = leftChild; + swap(arr, head, leftChild); + head = leftChild; order -= 1; } else { - swap(arr, root, rightChild); - root = rightChild; + swap(arr, head, rightChild); + head = rightChild; order -= 2; } } } - private static > void trinkle(T[] arr, int head, long p) { - int root = head; - while (p > 1) { - int order = Long.numberOfTrailingZeros(p); - p &= ~(1L << order); - int parentOrder = Long.numberOfTrailingZeros(p); - int parent = root - LP[order]; - - if (arr[parent].compareTo(arr[root]) >= 0) { - break; + private static > void trinkle(T[] arr, int head, long p, int q) { + while (q > 0) { + p &= ~(1L << q); + int prevHeapOrder = Long.numberOfTrailingZeros(p) + 1; + if (prevHeapOrder > 0) { + int parent = head - LP[q]; + if (arr[parent].compareTo(arr[head]) >= 0) { + break; + } + swap(arr, head, parent); + head = parent; } - swap(arr, root, parent); - root = parent; + q = prevHeapOrder; } - sift(arr, root, Long.numberOfTrailingZeros(p & -p)); + sift(arr, head, q); } private static void swap(T[] arr, int i, int j) { From 2cc773f8c627e22e7b4821ea37cc56953073aa23 Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Wed, 15 Oct 2025 00:10:59 +0530 Subject: [PATCH 8/9] fix: Final correction for smoothsort --- .../com/thealgorithms/sorts/SmoothSort.java | 94 ++++++------------- 1 file changed, 27 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 357471bd3878..0ad654fb4272 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -17,58 +17,16 @@ * @see Wikipedia: Smoothsort */ public final class SmoothSort { + // clang-format off /** * Private constructor to prevent instantiation of this utility class. */ - private SmoothSort() { - } + private SmoothSort() {} // Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1 private static final int[] LP = { - 1, - 1, - 3, - 5, - 9, - 15, - 25, - 41, - 67, - 109, - 177, - 287, - 465, - 753, - 1219, - 1973, - 3193, - 5167, - 8361, - 13529, - 21891, - 35421, - 57313, - 92735, - 150049, - 242785, - 392835, - 635621, - 1028457, - 1664079, - 2692537, - 4356617, - 7049155, - 11405773, - 18454929, - 29860703, - 48315633, - 78176337, - 126491971, - 204668309, - 331160281, - 535828591, - 866988873, + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, }; /** @@ -82,11 +40,11 @@ public static > void sort(T[] arr) { return; } int n = arr.length; + + int q = 0; // The order of the rightmost heap + long p = 1; // A bitmask representing the sizes of the heaps int head = 0; // The head of the list to be sorted - long p = 1; // A bitmask representing the sizes of the heaps. - int q = 1; // Size of the rightmost heap - // Phase 1: Build the forest of heaps while (head < n) { if ((p & 3) == 3) { // Combine the last two heaps @@ -96,7 +54,6 @@ public static > void sort(T[] arr) { p >>>= 1; q = 1; } - p |= 1L << q; while (head + LP[q] > n) { @@ -107,7 +64,6 @@ public static > void sort(T[] arr) { trinkle(arr, head - 1, p, q); } - // Phase 2: Deconstruct the forest to sort the array for (head = n - 1; head > 0; head--) { if (q <= 1) { p >>>= q; @@ -123,6 +79,24 @@ public static > void sort(T[] arr) { } } + private static > void trinkle(T[] arr, int head, long p, int q) { + while (q > 0) { + p &= ~(1L << q); + int prevHeapOrder = Long.numberOfTrailingZeros(p) + 1; + + if (prevHeapOrder > 0) { + int parent = head - LP[q]; + if (arr[parent].compareTo(arr[head]) >= 0) { + break; + } + swap(arr, head, parent); + head = parent; + } + q = prevHeapOrder; + } + sift(arr, head, q); + } + private static > void sift(T[] arr, int head, int order) { while (order >= 2) { int rightChild = head - 1; @@ -131,6 +105,7 @@ private static > void sift(T[] arr, int head, int order) if (arr[head].compareTo(arr[leftChild]) >= 0 && arr[head].compareTo(arr[rightChild]) >= 0) { break; } + if (arr[leftChild].compareTo(arr[rightChild]) > 0) { swap(arr, head, leftChild); head = leftChild; @@ -143,26 +118,11 @@ private static > void sift(T[] arr, int head, int order) } } - private static > void trinkle(T[] arr, int head, long p, int q) { - while (q > 0) { - p &= ~(1L << q); - int prevHeapOrder = Long.numberOfTrailingZeros(p) + 1; - if (prevHeapOrder > 0) { - int parent = head - LP[q]; - if (arr[parent].compareTo(arr[head]) >= 0) { - break; - } - swap(arr, head, parent); - head = parent; - } - q = prevHeapOrder; - } - sift(arr, head, q); - } - private static void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } + + // clang-format on } From 9804fc7b444deddaadd0f46d28f31a68a70721eb Mon Sep 17 00:00:00 2001 From: NarenCK11 Date: Wed, 15 Oct 2025 00:25:36 +0530 Subject: [PATCH 9/9] fix: Final correction for SmoothSort --- .../com/thealgorithms/sorts/SmoothSort.java | 98 +++++++++++-------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 0ad654fb4272..fb74373adc75 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -19,14 +19,16 @@ public final class SmoothSort { // clang-format off - /** - * Private constructor to prevent instantiation of this utility class. - */ + /** Private constructor to prevent instantiation of this utility class. */ private SmoothSort() {} // Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1 private static final int[] LP = { - 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873, + 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, + 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, + 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, + 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, + 866988873, }; /** @@ -41,58 +43,69 @@ public static > void sort(T[] arr) { } int n = arr.length; - int q = 0; // The order of the rightmost heap - long p = 1; // A bitmask representing the sizes of the heaps - int head = 0; // The head of the list to be sorted + int q = 0; // Order of the rightmost heap + long p = 1; // Bitmask representing heap sizes + int head = 0; // Current index in array while (head < n) { if ((p & 3) == 3) { - // Combine the last two heaps p >>>= 2; q += 2; } else { - p >>>= 1; - q = 1; + if ((p & 1) == 0) { + p = (p << 1) | 1; + q = 1; + } else { + p <<= 1; + q = 0; + } } - p |= 1L << q; + // Prevent out-of-bounds heap building while (head + LP[q] > n) { - p &= ~(1L << q); + p >>>= 1; q--; } + + trinkle(arr, head, p, q); head++; - trinkle(arr, head - 1, p, q); } - for (head = n - 1; head > 0; head--) { + // Sort the heaps + while (q != 0 || p != 1) { if (q <= 1) { - p >>>= q; - q = Long.numberOfTrailingZeros(p) + 1; + // Step back through the heaps + while ((p & 1) == 0) { + p >>>= 1; + q++; + } + p >>>= 1; } else { p &= ~(1L << q); q--; - int prevHeapOrder = Long.numberOfTrailingZeros(p) + 1; - sift(arr, head - LP[q], q); - p |= (1L << (prevHeapOrder - 1)); - trinkle(arr, head - 1, p, prevHeapOrder); + int right = head - 1; + int left = head - 1 - LP[q]; + sift(arr, left + LP[q], q); + sift(arr, right, q); } + head--; } } private static > void trinkle(T[] arr, int head, long p, int q) { - while (q > 0) { - p &= ~(1L << q); - int prevHeapOrder = Long.numberOfTrailingZeros(p) + 1; - - if (prevHeapOrder > 0) { - int parent = head - LP[q]; - if (arr[parent].compareTo(arr[head]) >= 0) { - break; - } - swap(arr, head, parent); - head = parent; + while (q > 1) { + int parent = head - LP[q]; + if (parent < 0) { + return; // prevent negative index } - q = prevHeapOrder; + + if (arr[head].compareTo(arr[parent]) <= 0) { + break; + } + + swap(arr, head, parent); + head = parent; + q -= 2; } sift(arr, head, q); } @@ -100,25 +113,32 @@ private static > void trinkle(T[] arr, int head, long p, private static > void sift(T[] arr, int head, int order) { while (order >= 2) { int rightChild = head - 1; - int leftChild = head - LP[order] + LP[order - 1]; + int leftChild = head - 1 - LP[order - 2]; - if (arr[head].compareTo(arr[leftChild]) >= 0 && arr[head].compareTo(arr[rightChild]) >= 0) { + if (leftChild < 0 || rightChild < 0) { + return; // safety check + } + + int largerChild = + arr[leftChild].compareTo(arr[rightChild]) >= 0 ? leftChild : rightChild; + + if (arr[head].compareTo(arr[largerChild]) >= 0) { break; } - if (arr[leftChild].compareTo(arr[rightChild]) > 0) { - swap(arr, head, leftChild); - head = leftChild; + swap(arr, head, largerChild); + head = largerChild; + + if (largerChild == leftChild) { order -= 1; } else { - swap(arr, head, rightChild); - head = rightChild; order -= 2; } } } private static void swap(T[] arr, int i, int j) { + if (i == j) return; T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;