level 5 · Linked structures
Circular Linked List
The tail points back at the head. There is no end — and that's the point.
what is it
Start here
Take a linked list and, instead of letting the last node point at NULL, point it back at the first one. The chain becomes a ring. There is now no end anywhere in the structure.
That one change breaks every habit you have. `while (cur !== null)` will never terminate — there is no null. You have to stop by a different rule: walk until you arrive back at the head. Get that wrong and your program hangs forever, and it will not tell you why.
So why do it? Because some things genuinely have no end. Turn-taking in a board game. Round-robin CPU scheduling, where each process gets a slice and then it's the next one's turn, forever. A playlist on repeat. A ring buffer. For all of these, 'the end' is a fiction you'd have to code around anyway.
It also has a quiet superpower: from any node you can reach every other node. In an ordinary list, if you're standing halfway along, everything behind you is unreachable. In a ring, just keep walking — you'll come back around to it.
And the reason you'll meet this in interviews: detecting an *accidental* ring. A bug that makes a list point back into itself turns your traversal into an infinite loop. Floyd's cycle detection — the fast and slow pointers — is how you catch it.
real-life analogy
Picture it
Everyone passes to the person on their left. There's no 'last person' — the ball just keeps going round. To take exactly one turn each, you don't watch for the end; you watch for the ball coming back to whoever started.
interactive visualization
Watch it run
The chain closes into a ring, then we walk two full laps.
- NULL
A circular linked list has no end. The last node doesn't point at NULL — it points back at the first one, closing the chain into a ring.
step 01/15
- moving
- in final place
- found it
space · play ← → · step
| 1 | // The tail points back at the head — there is no NULL. |
| 2 | function buildCircular(values) { |
| 3 | let head = null, tail = null; |
| 4 | for (const v of values) { |
| 5 | const node = new Node(v); |
| 6 | if (!head) head = node; |
| 7 | else tail.next = node; |
| 8 | tail = node; |
| 9 | } |
| 10 | tail.next = head; // close the loop |
| 11 | return head; |
| 12 | } |
| 13 | |
| 14 | // Careful: this loops forever without a stopping rule. |
| 15 | function walkOnce(head) { |
| 16 | let cur = head; |
| 17 | do { |
| 18 | visit(cur); |
| 19 | cur = cur.next; |
| 20 | } while (cur !== head); // stop when we come home |
| 21 | } |
variables right now
- length
- 0
the dry run · every step, in words
15 stepscomplexity
What it costs
- best case
- O(1) insert at head
- average
- O(n) to find
- worst case
- O(n) full lap
- extra memory
- O(n)
The same costs as a singly linked list — the ring doesn't make anything faster. What it changes is reachability: from any node you can reach every node, and traversal never naturally ends.
- O(1)
- O(log n)
- O(n) · this one
- O(n log n)
- O(n²)
common mistakes
Common traps
Looping with `while (cur !== null)`.
There is no null — it will never stop. Stop when you return to the head: `do { ... } while (cur !== head)`.
Forgetting to close the loop after building the list.
If the tail still points at NULL, you've just built an ordinary linked list. The final `tail.next = head` is what makes it circular.
Creating a ring by accident.
A bug that links a node back into the list turns every traversal into an infinite hang. Use Floyd's fast/slow pointers to detect a cycle — that's what LeetCode's 'Linked List Cycle' is really about.
quiz
Check yourself
Three questions. Get them all right to finish the lesson.
+65 XP01How do you know when to stop walking a circular linked list?
02What can you do from any node in a circular list that you can't in an ordinary one?
03Why is an *accidental* circular link so dangerous?
practice
Solve it on LeetCode
You've seen it run — now write it yourself. These are real LeetCode problems that use exactly this idea, from gentlest to toughest.