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..0ee788db2ff9 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedList.java @@ -0,0 +1,46 @@ +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.

+ * + *

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

+ * + *

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..ba5614a07916 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/lists/MiddleOfLinkedListTest.java @@ -0,0 +1,74 @@ +package com.thealgorithms.datastructures.lists; + +import static org.junit.jupiter.api.Assertions.assertEquals; +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 firstValue, int... remainingValues) { + SinglyLinkedListNode head = new SinglyLinkedListNode(firstValue); + SinglyLinkedListNode current = head; + + for (int i = 0; i < remainingValues.length; i++) { + current.next = new SinglyLinkedListNode(remainingValues[i]); + current = current.next; + } + return head; + } + + @Test + void middleNodeOddLength() { + SinglyLinkedListNode head = listOf(1, 2, 3, 4, 5); + 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 = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(4, middle.value); + } + + @Test + void middleNodeSingleElement() { + SinglyLinkedListNode head = listOf(42); + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(42, middle.value); + } + + @Test + void middleNodeTwoElementsReturnsSecond() { + SinglyLinkedListNode head = listOf(10, 20); + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(head)); + assertEquals(20, middle.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; + + SinglyLinkedListNode middle = Objects.requireNonNull(MiddleOfLinkedList.middleNode(first)); + assertEquals(3, middle.value); + + assertEquals(second, first.next); + assertEquals(third, second.next); + assertEquals(fourth, third.next); + assertNull(fourth.next); + } +}