Python Program to Detect Loop in Linked List
slow and fast, move slow by one step and fast by two steps, and check if they meet to detect a loop.Examples
How to Think About It
Algorithm
Code
class Node: def __init__(self, data): self.data = data self.next = None def detect_loop(head): slow = head fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return "Loop detected" return "No loop detected" # Example usage head = Node(1) head.next = Node(2) head.next.next = Node(3) head.next.next.next = Node(4) head.next.next.next.next = Node(5) # Creating a loop for testing head.next.next.next.next.next = head.next.next # 5 -> 3 print(detect_loop(head))
Dry Run
Let's trace the linked list with nodes 1->2->3->4->5 and a loop from 5 back to 3 through the code.
Initialize pointers
slow = Node(1), fast = Node(1)
First iteration
slow moves to Node(2), fast moves to Node(3)
Second iteration
slow moves to Node(3), fast moves to Node(5)
Third iteration
slow moves to Node(4), fast moves to Node(4) (because of loop)
Pointers meet
slow == fast at Node(4), loop detected
| Iteration | Slow Pointer | Fast Pointer |
|---|---|---|
| Start | 1 | 1 |
| 1 | 2 | 3 |
| 2 | 3 | 5 |
| 3 | 4 | 4 |
Why This Works
Step 1: Two pointers move at different speeds
The slow pointer moves one node at a time, while the fast pointer moves two nodes at a time.
Step 2: If no loop, fast pointer reaches end
If the linked list has no loop, the fast pointer will reach None and the function returns no loop.
Step 3: If loop exists, pointers meet
If there is a loop, the fast pointer will eventually catch up to the slow pointer inside the loop, confirming a cycle.
Alternative Approaches
class Node: def __init__(self, data): self.data = data self.next = None def detect_loop(head): visited = set() current = head while current: if current in visited: return "Loop detected" visited.add(current) current = current.next return "No loop detected" # Example usage head = Node(1) head.next = Node(2) head.next.next = Node(3) head.next.next.next = Node(4) head.next.next.next.next = Node(5) head.next.next.next.next.next = head.next.next print(detect_loop(head))
class Node: def __init__(self, data): self.data = data self.next = None def detect_loop(head): current = head while current: if hasattr(current, 'visited'): return "Loop detected" setattr(current, 'visited', True) current = current.next return "No loop detected" # Example usage head = Node(1) head.next = Node(2) head.next.next = Node(3) head.next.next.next = Node(4) head.next.next.next.next = Node(5) head.next.next.next.next.next = head.next.next print(detect_loop(head))
Complexity: O(n) time, O(1) space
Time Complexity
The algorithm visits each node at most a constant number of times, so it runs in linear time relative to the number of nodes.
Space Complexity
Only two pointers are used, so the space used is constant, regardless of list size.
Which Approach is Fastest?
Floyd’s Cycle Detection is fastest and uses least memory compared to using a set or modifying nodes.
| Approach | Time | Space | Best For |
|---|---|---|---|
| Floyd’s Cycle Detection | O(n) | O(1) | Efficient detection without extra memory |
| Using a set | O(n) | O(n) | Simple to understand but uses extra memory |
| Modifying node data | O(n) | O(1) | Unsafe, can cause side effects |
fast and fast.next are not None before moving pointers.