How to Detect a Cycle in a Linked List (Floyd’s Algorithm Explained)

How to Detect a Cycle in a Linked List (Floyd’s Algorithm Explained)

A clear, beginner-friendly guide to finding loops in a linked list — using Floyd’s Tortoise and Hare algorithm, with visual step-by-step tracing, Python code, and how to find exactly where the cycle starts.

Last updated: April 18, 2026  |  Topic: Data Structures  |  Level: Beginner to Intermediate

What You’ll Learn

  • What a cycle (loop) in a linked list is and why it’s a problem.
  • Three ways to detect a cycle — and which one is best.
  • How Floyd’s Tortoise and Hare algorithm works, step by step.
  • How to find the exact node where the cycle starts.
  • Time complexity: O(n). Space complexity: O(1).
  • A complete, working Python implementation.
  • Why this is one of the most common coding interview questions.

Advertisement

1. What Is a Cycle in a Linked List?

A normal linked list ends when a node points to null. A cycle (also called a loop) exists when some node’s next pointer points back to an earlier node in the list — creating a loop that has no end.

Normal linked list (no cycle):
1 → 2 → 3 → 4 → 5 → null

Linked list with a cycle:
1 → 2 → 3 → 4 → 5
              ↑       |
              └───────┘
  (node 5's next points back to node 3)

In the cycled example, if you start at node 1 and keep following .next, you’ll visit: 1, 2, 3, 4, 5, 3, 4, 5, 3, 4, 5 … forever. You’d never reach null.

2. Why Is a Cycle a Problem?

Cycles in linked lists are almost always bugs — usually caused by a coding mistake that accidentally connects a node back to a previous node. They cause:

  • Infinite loops: Any traversal (printing, searching, length calculation) loops forever.
  • Memory issues: Garbage collectors in some languages can’t reclaim cycled nodes because they always appear “reachable.”
  • Wrong results: Algorithms like “find the last node” never terminate.

Detecting and removing cycles is therefore an important defensive programming skill and a favourite coding interview problem.

3. Three Ways to Detect a Cycle

MethodIdeaTimeSpaceBest?
Hash SetStore each visited node in a set. If you see a node you’ve already stored, a cycle exists.O(n)O(n)Simple but uses extra memory
Modifying nodesMark each node as visited (e.g., set a flag). If you reach an already-marked node, cycle found.O(n)O(1)Destructive — modifies the list
Floyd’s Two-PointerUse a slow pointer (1 step) and a fast pointer (2 steps). If they meet, a cycle exists.O(n)O(1)✅ Best — no extra memory, non-destructive

Floyd’s algorithm is the gold standard. It’s what interviewers expect and what you should know cold.

4. Floyd’s Tortoise and Hare Algorithm

The intuition is beautifully simple: imagine two runners on a circular track. One runs slowly (1 lap/hour), the other runs fast (2 laps/hour). If the track is circular, the fast runner will eventually lap the slow runner and they’ll be at the same point again. If the track is straight (no loop), the fast runner just reaches the end first.

Applied to a linked list:

  • Slow pointer (tortoise) — moves 1 node at a time.
  • Fast pointer (hare) — moves 2 nodes at a time.
If no cycle: The fast pointer hits null. Done — no cycle.
If cycle exists: The fast pointer enters the cycle and keeps lapping the slow pointer until they meet at the same node.
Advertisement

5. Visual Step-by-Step Trace

Let’s trace Floyd’s algorithm on this linked list:

Nodes:  1 → 2 → 3 → 4 → 5 → 6
                ↑               |
                └───────────────┘
(node 6's next points back to node 3)

Start: slow = 1, fast = 1

StepSlow (moves 1)Fast (moves 2)Same node?
Start11
123No
235No
343 (6→3)No
455 (3→4→5)Yes! Cycle detected.

They meet at node 5. Cycle confirmed.

6. How to Find Where the Cycle Starts

Once we know a cycle exists (pointers met inside the cycle), we can find the exact node where the cycle begins. Here’s the trick:

  1. Keep the fast pointer at the meeting point.
  2. Reset the slow pointer back to the head of the list.
  3. Move both pointers one step at a time.
  4. Where they meet again = the start of the cycle.
Why does this work?
Let:
  L = distance from head to cycle start
  C = length of the cycle
  k = distance from cycle start to meeting point

When slow and fast meet: slow has traveled L + k steps. Fast has traveled L + k + C steps (one full cycle ahead).
Since fast moves 2× slow: 2(L+k) = L+k+C → L = C−k.

This means: distance from head to cycle start = distance from meeting point to cycle start (going forward in the cycle).
So moving one pointer from head and one from the meeting point at the same speed, they’ll arrive at the cycle start simultaneously.

Trace — Finding Cycle Start

After detection: slow = fast = node 5 (meeting point)
Reset slow to head (node 1). Fast stays at node 5.

Step 1: slow → 2,  fast → 6
Step 2: slow → 3,  fast → 3   ← Meet at node 3!

Cycle starts at node 3. ✓ (matches our diagram above)

7. Python Implementation

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

def has_cycle(head):
    """Returns True if the linked list has a cycle."""
    slow = head
    fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return True
    return False

def find_cycle_start(head):
    """Returns the node where the cycle begins, or None."""
    slow = fast = head
    # Phase 1: detect
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            break
    else:
        return None  # no cycle

    # Phase 2: find start
    slow = head
    while slow != fast:
        slow = slow.next
        fast = fast.next
    return slow  # cycle start node

# Build a test list: 1→2→3→4→5→6→(back to 3)
nodes = [Node(i) for i in range(1, 7)]
for i in range(5):
    nodes[i].next = nodes[i+1]
nodes[5].next = nodes[2]   # cycle: 6 → 3

print(has_cycle(nodes[0]))                    # True
print(find_cycle_start(nodes[0]).data)        # 3

Advertisement

8. Time and Space Complexity

MethodTimeSpace
Floyd’s Two-PointerO(n)O(1)
Hash SetO(n)O(n)

Floyd’s algorithm is linear in time: in the worst case, the slow pointer travels n steps before meeting the fast pointer (which has done at most 2n steps). Only two pointer variables are used — no arrays, sets, or extra nodes — so space is O(1).

9. Worked Examples

Example 1 — No Cycle

List: 1 → 2 → 3 → null

slow=1, fast=1
Step 1: slow=2, fast=3
Step 2: slow=3, fast=null → fast is null, STOP.
Result: No cycle. ✓

Example 2 — Entire List Is a Cycle

List: 1 → 2 → 3 → (back to 1)

slow=1, fast=1
Step 1: slow=2, fast=3
Step 2: slow=3, fast=2
Step 3: slow=1, fast=1 → Meet! Cycle detected.
Cycle start: reset slow=head(1), fast stays at 1.
They already meet at node 1 → cycle starts at node 1. ✓

Example 3 — Single Node Pointing to Itself

List: 1 → (back to 1)

slow=1, fast=1
Step 1: slow=1 (1→1), fast=1 (1→1→1) → slow==fast.
Cycle detected immediately. Cycle start = node 1. ✓

Advertisement

10. Five Common Mistakes

Mistake 1 — Not checking fast.next before moving fast two steps

The fast pointer moves as fast.next.next. If fast.next is null, accessing fast.next.next throws a NullPointerException. Always check if fast and fast.next before each step.

Mistake 2 — Starting fast at head.next instead of head

Some implementations start slow at head and fast at head.next. This works but complicates the cycle-start-finding phase. Starting both at head is simpler and avoids off-by-one bugs.

Mistake 3 — Using a hash set and comparing node values, not node references

If your linked list contains duplicate values (e.g., 1 → 2 → 1), comparing values will give false positives. When using a hash set, store the node object reference (memory address), not the data value.

Mistake 4 — Forgetting the cycle-start-finding is a separate phase

Many beginners think the meeting point of slow and fast IS the cycle start. It’s not — it’s just somewhere inside the cycle. You need the second phase (reset slow to head, move both one step at a time) to find the actual cycle start.

Mistake 5 — Assuming the algorithm works for doubly linked lists without changes

Floyd’s algorithm assumes you only follow .next pointers. A doubly linked list with a cycle in its .prev pointers requires separate detection logic. For singly linked lists, the algorithm works as described.

11. Frequently Asked Questions

What is Floyd’s cycle detection algorithm?

Floyd’s cycle detection (Tortoise and Hare) uses two pointers moving at different speeds through the linked list. The slow pointer moves one step at a time; the fast pointer moves two steps. If a cycle exists, they will meet inside it. If the fast pointer reaches null, there is no cycle. It runs in O(n) time and uses O(1) extra space.

What is the time and space complexity of cycle detection in a linked list?

Floyd’s algorithm: O(n) time, O(1) space. The pointers meet within at most 2n steps, and only two pointer variables are used. The hash set approach is also O(n) time but uses O(n) space to store visited nodes — far less efficient for large lists.

How do you find where the cycle starts in a linked list?

After the fast and slow pointers meet (cycle detected), reset the slow pointer to the head of the list. Keep the fast pointer at the meeting point. Now move both pointers one step at a time. The node where they meet next is the start of the cycle. This relies on the mathematical property that the distance from head to cycle start equals the remaining distance from the meeting point to cycle start.

Why use two pointers instead of a hash set for cycle detection?

A hash set works but requires O(n) extra memory to store all visited node references. Floyd’s two-pointer approach uses only O(1) memory — just two pointer variables regardless of list size. For large datasets or memory-constrained systems, Floyd’s is always the better choice. It’s also the expected answer in coding interviews.

12. Next Steps

Advertisement

Leave a Comment