Skip to content

Floyd's Cycle Detection Visualizer

Singlyn = 6≈ 72 B
last.next = node 2
from head:12→7→33→5→21→48→↺ 33 (cycle!)
1/11

What is Floyd's cycle detection algorithm?

Floyd's cycle detection — the tortoise and hare algorithm — tells whether a linked list loops back on itself by moving two pointers through it: slow one node per step and fast two. If fast reaches NULL there is no cycle; if the two ever meet there is one, and restarting one pointer at the head and moving both one step at a time makes them meet again exactly where the cycle begins. It runs in O(n) time with O(1) extra memory.

How it works

  1. Put both pointers on the head: slow = fast = head.
  2. Phase 1: while fast and fast.next are not NULL, move slow one node and fast two nodes.
  3. If fast runs off the end, the list is NULL-terminated — there is no cycle.
  4. If slow == fast (the same node, not just the same value), a cycle exists.
  5. Phase 2: move slow back to the head and advance both pointers one node at a time; the node where they meet is the start of the cycle.

Why the hare always catches the tortoise

If there is no cycle, fast reaches the end first — after about n/2 steps — and the algorithm stops. If there is a cycle, both pointers eventually enter it and can never leave. From then on, look at the distance from slow forward to fast around the loop: every step fast gains one node, so the gap shrinks by exactly one. A gap that shrinks by one per step cannot jump over zero, so the pointers must land on the same node, and they do so within one lap — before slow has gone once around the cycle. That bound is what makes phase 1 O(n).

Why phase 2 finds the start of the cycle

Let μ be the number of steps from the head to the first node of the cycle, λ the cycle's length, and suppose the pointers meet k steps past the cycle's start. At the meeting, slow has walked μ + k nodes and fast twice as many, 2(μ + k). The extra distance fast covered is a whole number of laps: 2(μ + k) − (μ + k) = μ + k = m·λ for some whole number m.

Rearranged, μ = m·λ − k. So a pointer standing at the meeting point that walks μ more steps has travelled k + μ = m·λ from the start of the cycle — whole laps — and lands exactly on the cycle's start. A second pointer walking μ steps from the head lands there too. Neither knows μ, and neither needs to: move both one step at a time and the first node they share is the answer.

Worked example

This page opens with 12 → 7 → 33 → 5 → 21 → 48 and the last node pointing back at index 2 (value 33), so μ = 2 and the cycle 33 → 5 → 21 → 48 has length λ = 4.

  • Phase 1, step 1: slow = 7, fast = 33.
  • Step 2: slow = 33, fast = 21.
  • Step 3: slow = 5, fast = 33 (21 → 48 → back to 33).
  • Step 4: slow = 21, fast = 21 — they meet, so there is a cycle. The meeting point is k = 2 steps past 33, and μ + k = 4 = 1·λ, as the proof predicts.
  • Phase 2: slow restarts at 12 while fast stays on 21. After one step slow = 7 and fast = 48; after two, both are on 33.

They meet on 33 after μ = 2 steps: the cycle starts at index 2, and walking once around from 33 back to 33 gives its length, 4. Press play to watch both phases; the demo removes the extra link again when it finishes.

Cycle length and removing the cycle

Once you have a meeting point inside the loop, two more facts are cheap to get:

  • Cycle length λ: keep one pointer fixed and walk the other until it comes back — λ steps.
  • Remove the cycle: after phase 2 gives the start node, walk around the loop to the node whose next is the start and set that next to NULL. The list is an ordinary NULL-terminated list again.

Both add only O(λ) work and still use O(1) memory.

Alternatives: a hash set or Brent's algorithm

The obvious approach is to remember every node you visit in a hash set and stop when you see one twice. It is just as fast — O(n) — and finds the start of the cycle immediately, but it needs O(n) extra memory. Floyd's algorithm trades that memory for a second pass.

Brent's algorithm refines the idea: it moves one pointer and periodically teleports the other to it at power-of-two intervals, still with O(1) memory and usually fewer steps. Both algorithms work on any sequence produced by repeatedly applying a function, x → f(x), which is why the same idea appears in Pollard's rho factoring, in the analysis of pseudo-random number generators, and in the interview problem "find the duplicate number" (LeetCode 287), where array values act as next pointers.

Common mistakes

  • Double-stepping without a NULL check. Reading fast.next.next when fast.next is NULL crashes on an even-length list; test fast and fast.next before every double step.
  • Comparing values instead of nodes. Two different nodes may hold the same number; compare identity (is in Python, pointer equality in C).
  • Starting the pointers on different nodes, for example fast = head.next. Detection still works, but the phase-2 arithmetic no longer lines up and the reported start node is wrong.
  • Forgetting the empty list, or a one-node list without a self-loop.

Time and space complexity

CaseTimeSpaceWhy
Detect a cycle (phase 1)O(n)O(1)At most μ + λ steps: reach the cycle, then the gap closes within one lap.
Find the cycle start (phase 2)O(n)O(1)Exactly μ more steps, where μ is the distance from the head to the cycle.
Cycle lengthO(λ)O(1)Walk once around the loop from the meeting point.
Hash-set methodO(n)O(n)Simple, but stores every visited node.

Floyd's Cycle Detection in Python

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


class LinkedList:
    def __init__(self):
        self.head = None  # first node

    def detect_cycle(self):
        slow = fast = self.head
        while fast is not None and fast.next is not None:
            slow = slow.next
            fast = fast.next.next
            if slow is fast:
                break
        if fast is None or fast.next is None:
            return None  # they never met: no cycle
        slow = self.head
        while slow is not fast:  # 1 step each
            slow = slow.next
            fast = fast.next
        return slow  # cycle start

The visualizer above shows the same code in Python, C++, Java and JavaScript.

Frequently asked questions

Why does the fast pointer move two steps instead of three?

Any speed difference detects a cycle, but with speeds 1 and 2 the gap closes by exactly one node per step, so the pointers cannot skip past each other and meet within one lap. Speed 2 is also what makes the phase-2 trick land exactly on the start of the cycle.

What is the time complexity of Floyd's cycle detection?

O(n) time and O(1) space. Phase 1 takes at most μ + λ steps (the part before the loop plus one lap), phase 2 exactly μ steps, and only two pointers are stored.

How do you find where a cycle begins in a linked list?

After slow and fast meet, move one pointer back to the head and advance both one node at a time. They meet again at the first node of the cycle, because the head-to-cycle distance equals the meeting-point-to-cycle-start distance, modulo the cycle length.

Is Floyd's algorithm the same as the tortoise and hare algorithm?

Yes. "Tortoise and hare" is the nickname for Floyd's cycle-finding algorithm: the slow pointer is the tortoise and the fast pointer is the hare. The same two-speed idea also finds the middle of a list in one pass.

Can Floyd's algorithm detect a cycle in a graph?

Only when every node has exactly one successor, as in a linked list or a function x → f(x). For general directed graphs, use depth-first search and look for a back edge to a node that is still on the recursion stack.

Keep learning

Last updated