Problem Description: A cycle in a linked list occurs when a node’s next
pointer points back to one of the previous nodes, creating a loop. This means traversing the linked list will not end; it will keep looping indefinitely. Detecting such cycles is an important task in linked list operations, particularly when dealing with dynamic memory or linked data structures.
Key Idea: The most common and efficient algorithm for detecting a cycle in a linked list is Floyd’s Cycle Detection Algorithm (also known as the “Tortoise and Hare” algorithm). This algorithm uses two pointers:
- A slow pointer (
slow
), which moves one step at a time. - A fast pointer (
fast
), which moves two steps at a time.
If there is a cycle, the fast
pointer will eventually meet the slow
pointer. If there is no cycle, the fast
pointer will reach the end of the linked list.
Example
Example 1: Linked List with a Cycle
Consider the linked list:
1 -> 2 -> 3 -> 4 -> 5
^ |
|________|
Here, the 5
node points back to the 3
node, creating a cycle. The algorithm should detect this.
Example 2: Linked List without a Cycle
1 -> 2 -> 3 -> 4 -> 5 -> null
Here, the 5
node points to null
. The algorithm should confirm there is no cycle.
Kotlin Solution
Below is a Kotlin implementation of the cycle detection algorithm:
class ListNode(var value: Int) {
var next: ListNode? = null
}
fun hasCycle(head: ListNode?): Boolean {
if (head == null || head.next == null) return false
var slow = head
var fast = head
while (fast != null && fast.next != null) {
slow = slow?.next // Move slow pointer by 1 step
fast = fast.next?.next // Move fast pointer by 2 steps
if (slow == fast) {
// Cycle detected
return true
}
}
// No cycle
return false
}
fun main() {
// Example 1: Linked List with a Cycle
val node1 = ListNode(1)
val node2 = ListNode(2)
val node3 = ListNode(3)
val node4 = ListNode(4)
val node5 = ListNode(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node3 // Creates a cycle
println("Does the list have a cycle? ${hasCycle(node1)}") // Output: true
// Example 2: Linked List without a Cycle
val nodeA = ListNode(1)
val nodeB = ListNode(2)
val nodeC = ListNode(3)
nodeA.next = nodeB
nodeB.next = nodeC
println("Does the list have a cycle? ${hasCycle(nodeA)}") // Output: false
}
Explanation of the Code
- Node Definition:
- A
ListNode
class is defined, which has a value (value
) and a reference to the next node (next
).
- A
- Cycle Detection Function:
- The function
hasCycle
takes the head of the linked list as input. - It uses two pointers (
slow
andfast
). - A
while
loop is used to traverse the list. Iffast
orfast.next
isnull
, there is no cycle. - If
slow
equalsfast
, a cycle is detected.
- The function
- Test Cases in
main
:- Two examples are tested: one with a cycle and one without a cycle.
Complexity Analysis
- Time Complexity: O(n)O(n)O(n), where nnn is the number of nodes. Both pointers traverse the list at most once.
- Space Complexity: O(1)O(1)O(1), as no extra space is used apart from pointers.
This efficient solution ensures quick detection of cycles in linked lists and is widely used in practice.