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 1/6] 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:
+ *
+ * - Best case: O(n) for already sorted input
+ * - Average case: O(n log n)
+ * - Worst case: O(n log n)
+ *
+ *
+ * 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 2/6] 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 3/6] 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:
+ *
+ * - Time: {@code O(n)}
+ * - Space: {@code O(1)}
+ *
+ */
+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 4/6] 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:
*
* - Time: {@code O(n)}
From ba7df6a0747a8c1ff92b4494f426e346d80beab2 Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
Date: Fri, 16 Jan 2026 11:27:22 +0200
Subject: [PATCH 5/6] test: refactor MiddleOfLinkedListTest to improve
readability and assertions
---
.../lists/MiddleOfLinkedListTest.java | 21 ++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
index b4f1a48a6ceb..b18d7f00dbd0 100644
--- a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
@@ -1,6 +1,7 @@
package com.thealgorithms.datastructures.lists;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
@@ -24,25 +25,33 @@ private static SinglyLinkedListNode listOf(int... values) {
@Test
void middleNodeOddLength() {
SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5);
- assertEquals(3, MiddleOfLinkedList.middleNode(head).value);
+ SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
+ assertNotNull(middle);
+ assertEquals(3, middle.value);
}
@Test
void middleNodeEvenLengthReturnsSecondMiddle() {
SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5, 6);
- assertEquals(4, MiddleOfLinkedList.middleNode(head).value);
+ SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
+ assertNotNull(middle);
+ assertEquals(4, middle.value);
}
@Test
void middleNodeSingleElement() {
SinglyLinkedListNode head = listOf(42);
- assertEquals(42, MiddleOfLinkedList.middleNode(head).value);
+ SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
+ assertNotNull(middle);
+ assertEquals(42, middle.value);
}
@Test
void middleNodeTwoElementsReturnsSecond() {
SinglyLinkedListNode head = listOf(10, 20);
- assertEquals(20, MiddleOfLinkedList.middleNode(head).value);
+ SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
+ assertNotNull(middle);
+ assertEquals(20, middle.value);
}
@Test
@@ -61,7 +70,9 @@ void middleNodeDoesNotModifyListStructure() {
second.next = third;
third.next = fourth;
- assertEquals(3, MiddleOfLinkedList.middleNode(first).value);
+ SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(first);
+ assertNotNull(middle);
+ assertEquals(3, middle.value);
assertEquals(second, first.next);
assertEquals(third, second.next);
From 5768de2335420acf32c818fff9751e5a9b495462 Mon Sep 17 00:00:00 2001
From: Ahmed Allam <60698204+AllamF5J@users.noreply.github.com>
Date: Fri, 16 Jan 2026 11:37:34 +0200
Subject: [PATCH 6/6] test: refactor MiddleOfLinkedListTest for improved null
safety and readability
---
.../lists/MiddleOfLinkedListTest.java | 30 +++++++------------
1 file changed, 11 insertions(+), 19 deletions(-)
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
index b18d7f00dbd0..ba5614a07916 100644
--- a/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java
@@ -1,22 +1,19 @@
package com.thealgorithms.datastructures.lists;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import java.util.Objects;
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]);
+ private static SinglyLinkedListNode listOf(int firstValue, int... remainingValues) {
+ SinglyLinkedListNode head = new SinglyLinkedListNode(firstValue);
SinglyLinkedListNode current = head;
- for (int i = 1; i < values.length; i++) {
- current.next = new SinglyLinkedListNode(values[i]);
+
+ for (int i = 0; i < remainingValues.length; i++) {
+ current.next = new SinglyLinkedListNode(remainingValues[i]);
current = current.next;
}
return head;
@@ -25,32 +22,28 @@ private static SinglyLinkedListNode listOf(int... values) {
@Test
void middleNodeOddLength() {
SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5);
- SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
- assertNotNull(middle);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
assertEquals(3, middle.value);
}
@Test
void middleNodeEvenLengthReturnsSecondMiddle() {
SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5, 6);
- SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
- assertNotNull(middle);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
assertEquals(4, middle.value);
}
@Test
void middleNodeSingleElement() {
SinglyLinkedListNode head = listOf(42);
- SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
- assertNotNull(middle);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
assertEquals(42, middle.value);
}
@Test
void middleNodeTwoElementsReturnsSecond() {
SinglyLinkedListNode head = listOf(10, 20);
- SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(head);
- assertNotNull(middle);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head));
assertEquals(20, middle.value);
}
@@ -70,8 +63,7 @@ void middleNodeDoesNotModifyListStructure() {
second.next = third;
third.next = fourth;
- SinglyLinkedListNode middle = MiddleOfLinkedList.middleNode(first);
- assertNotNull(middle);
+ SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(first));
assertEquals(3, middle.value);
assertEquals(second, first.next);