From a8ef94149acceaaaf5143b234ef9c89c766fd30c Mon Sep 17 00:00:00 2001 From: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com> Date: Fri, 9 Jan 2026 02:48:38 +0200 Subject: [PATCH 01/10] feat: implement Smooth Sort algorithm with detailed JavaDoc and test class --- .../com/thealgorithms/sorts/SmoothSort.java | 173 ++++++++++++++++++ .../thealgorithms/sorts/SmoothSortTest.java | 8 + 2 files changed, 181 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..7e881e84ee62 --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -0,0 +1,173 @@ +package com.thealgorithms.sorts; + +/** + * Smooth Sort is an in-place, comparison-based sorting algorithm proposed by Edsger W. Dijkstra (1981). + * + *

It can be viewed as a variant of heapsort that maintains a forest of heap-ordered Leonardo trees + * (trees whose sizes are Leonardo numbers). The algorithm is adaptive: when the input is already + * sorted or nearly sorted, the heap invariants are often satisfied and the expensive rebalancing + * operations do little work, yielding near-linear behavior. + * + *

Time Complexity: + *

+ * + *

Space Complexity: O(1) auxiliary space (in-place). + * + * @see Smoothsort + * @see Leonardo numbers + * @see SortAlgorithm + */ +public class SmoothSort implements SortAlgorithm { + + /** + * Leonardo numbers (L(0) = L(1) = 1, L(k+2) = L(k+1) + L(k) + 1) up to the largest value that + * fits into a signed 32-bit integer. + */ + private static final int[] LEONARDO = { + 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, 1402817465 + }; + + /** + * Sorts the given array in ascending order using Smooth Sort. + * + * @param array the array to sort + * @param the element type + * @return the sorted array + */ + @Override + public > T[] sort(final T[] array) { + if (array.length < 2) { + return array; + } + + final int last = array.length - 1; + + // The forest shape is encoded as (p, pshift): p is a bit-vector of present tree orders, + // shifted right by pshift. pshift is the order of the rightmost (current) Leonardo tree. + long p = 1L; + int pshift = 1; + + int head = 0; + while (head < last) { + if ((p & 3L) == 3L) { + sift(array, pshift, head); + p >>>= 2; + pshift += 2; + } else { + // Add a new singleton tree; if it will not be merged anymore, we must fully trinkle. + if (LEONARDO[pshift - 1] >= last - head) { + trinkle(array, p, pshift, head, false); + } else { + // This tree will be merged later, so it is enough to restore its internal heap property. + sift(array, pshift, head); + } + + if (pshift == 1) { + // If L(1) is used, the new singleton is L(0). + p <<= 1; + pshift = 0; + } else { + // Otherwise, shift to order 1 and append a singleton of order 1. + p <<= (pshift - 1); + pshift = 1; + } + } + + p |= 1L; + head++; + } + + trinkle(array, p, pshift, head, false); + + // Repeatedly remove the maximum (always at head) by shrinking the heap region. + while (pshift != 1 || p != 1L) { + if (pshift <= 1) { + // Rightmost tree is a singleton (order 0 or 1). Move to the previous tree root. + final long mask = p & ~1L; + final int shift = Long.numberOfTrailingZeros(mask); + p >>>= shift; + pshift += shift; + } else { + // Split a tree of order (pshift) into two children trees of orders (pshift-1) and (pshift-2). + p <<= 2; + p ^= 7L; + pshift -= 2; + + trinkle(array, p >>> 1, pshift + 1, head - LEONARDO[pshift] - 1, true); + trinkle(array, p, pshift, head - 1, true); + } + + head--; + } + + return array; + } + + private static > void sift(final T[] array, int order, int root) { + final T value = array[root]; + + while (order > 1) { + final int right = root - 1; + final int left = root - 1 - LEONARDO[order - 2]; + + if (!SortUtils.less(value, array[left]) && !SortUtils.less(value, array[right])) { + break; + } + + if (!SortUtils.less(array[left], array[right])) { + array[root] = array[left]; + root = left; + order -= 1; + } else { + array[root] = array[right]; + root = right; + order -= 2; + } + } + + array[root] = value; + } + + private static > void trinkle(final T[] array, long p, int order, int root, boolean trusty) { + final T value = array[root]; + + while (p != 1L) { + final int stepson = root - LEONARDO[order]; + + if (!SortUtils.less(value, array[stepson])) { + break; + } + + if (!trusty && order > 1) { + final int right = root - 1; + final int left = root - 1 - LEONARDO[order - 2]; + + if (!SortUtils.less(array[right], array[stepson]) || !SortUtils.less(array[left], array[stepson])) { + break; + } + } + + array[root] = array[stepson]; + root = stepson; + + final long mask = p & ~1L; + final int shift = Long.numberOfTrailingZeros(mask); + p >>>= shift; + order += shift; + trusty = false; + } + + if (!trusty) { + array[root] = value; + sift(array, order, root); + } + } +} 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..8df0502e80e7 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/SmoothSortTest.java @@ -0,0 +1,8 @@ +package com.thealgorithms.sorts; + +public class SmoothSortTest extends SortingAlgorithmTest { + @Override + SortAlgorithm getSortAlgorithm() { + return new SmoothSort(); + } +} From 8bf1a0ea22f42dcb5ee88d004d7e1a27fceec26d Mon Sep 17 00:00:00 2001 From: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com> Date: Fri, 9 Jan 2026 03:46:48 +0200 Subject: [PATCH 02/10] style: format LEONARDO array for improved readability with clang-format --- src/main/java/com/thealgorithms/sorts/SmoothSort.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/SmoothSort.java b/src/main/java/com/thealgorithms/sorts/SmoothSort.java index 7e881e84ee62..c45d6f1f02b2 100644 --- a/src/main/java/com/thealgorithms/sorts/SmoothSort.java +++ b/src/main/java/com/thealgorithms/sorts/SmoothSort.java @@ -27,13 +27,8 @@ public class SmoothSort implements SortAlgorithm { * Leonardo numbers (L(0) = L(1) = 1, L(k+2) = L(k+1) + L(k) + 1) up to the largest value that * fits into a signed 32-bit integer. */ - private static final int[] LEONARDO = { - 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, 1402817465 - }; + private static final int[] LEONARDO = {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, 1402817465}; /** * Sorts the given array in ascending order using Smooth Sort. From b6c1e5c914e51b33921446e437f8a173c01d3a78 Mon Sep 17 00:00:00 2001 From: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com> Date: Fri, 16 Jan 2026 10:36:02 +0200 Subject: [PATCH 03/10] feat: add MiddleOfLinkedList class and corresponding test cases --- .../lists/MiddleOfLinkedList.java | 44 ++++++++++++ .../lists/MiddleOfLinkedListTest.java | 71 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java create mode 100644 src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java new file mode 100644 index 000000000000..d4c5775e93f2 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java @@ -0,0 +1,44 @@ +package com.thealgorithms.datastructures.lists; + +/** + * Returns the middle node of a singly linked list using the two-pointer technique. + * + *

The {@code slow} pointer advances by one node per iteration while {@code fast} advances by two. + * When {@code fast == null} or {@code fast.next == null}, {@code slow} points to the middle node. + * For even-length lists, this returns the second middle node.

+ * + *

This method does not modify the input list.

+ * + *

Complexity:

+ * + */ +public final class MiddleOfLinkedList { + + private MiddleOfLinkedList() { + } + + /** + * Returns the middle node of the list. + * + * @param head the head of the singly linked list; may be {@code null} + * @return the middle node (second middle for even-sized lists), or {@code null} if {@code head} is {@code null} + */ + public static SinglyLinkedListNode middleNode(final SinglyLinkedListNode head) { + if (head == null) { + return null; + } + + SinglyLinkedListNode slow = head; + SinglyLinkedListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + return slow; + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java new file mode 100644 index 000000000000..b4f1a48a6ceb --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java @@ -0,0 +1,71 @@ +package com.thealgorithms.datastructures.lists; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +public class MiddleOfLinkedListTest { + + private static SinglyLinkedListNode listOf(int... values) { + if (values == null || values.length == 0) { + return null; + } + + SinglyLinkedListNode head = new SinglyLinkedListNode(values[0]); + SinglyLinkedListNode current = head; + for (int i = 1; i < values.length; i++) { + current.next = new SinglyLinkedListNode(values[i]); + current = current.next; + } + return head; + } + + @Test + void middleNodeOddLength() { + SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5); + assertEquals(3, MiddleOfLinkedList.middleNode(head).value); + } + + @Test + void middleNodeEvenLengthReturnsSecondMiddle() { + SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5, 6); + assertEquals(4, MiddleOfLinkedList.middleNode(head).value); + } + + @Test + void middleNodeSingleElement() { + SinglyLinkedListNode head = listOf(42); + assertEquals(42, MiddleOfLinkedList.middleNode(head).value); + } + + @Test + void middleNodeTwoElementsReturnsSecond() { + SinglyLinkedListNode head = listOf(10, 20); + assertEquals(20, MiddleOfLinkedList.middleNode(head).value); + } + + @Test + void middleNodeNullHead() { + assertNull(MiddleOfLinkedList.middleNode(null)); + } + + @Test + void middleNodeDoesNotModifyListStructure() { + SinglyLinkedListNode first = new SinglyLinkedListNode(1); + SinglyLinkedListNode second = new SinglyLinkedListNode(2); + SinglyLinkedListNode third = new SinglyLinkedListNode(3); + SinglyLinkedListNode fourth = new SinglyLinkedListNode(4); + + first.next = second; + second.next = third; + third.next = fourth; + + assertEquals(3, MiddleOfLinkedList.middleNode(first).value); + + assertEquals(second, first.next); + assertEquals(third, second.next); + assertEquals(fourth, third.next); + assertNull(fourth.next); + } +} From d46a06544ae83597fd716adc64e6098e2234432b Mon Sep 17 00:00:00 2001 From: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com> Date: Fri, 16 Jan 2026 10:48:27 +0200 Subject: [PATCH 04/10] docs: update documentation for MiddleOfLinkedList class --- .../thealgorithms/datastructures/lists/MiddleOfLinkedList.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java index d4c5775e93f2..0ee788db2ff9 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java @@ -9,6 +9,8 @@ * *

This method does not modify the input list.

* + *

Reference: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare

+ * *

Complexity:

*