Skip to content
DSA linked lists 7 min read

Circular Linked List: The Looping Chain Explained

A circular linked list is a linked list whose last node points back to the first node instead of to null, so the chain forms a closed loop. There is no “end” — following next forever cycles through the nodes endlessly. This shape is perfect when you need to cycle through items repeatedly, such as round-robin scheduling or a looping playlist. It can be built on top of a singly or doubly linked list.

How it differs

In a normal list the tail’s next is null. In a circular list the tail’s next is the head. A handy convention is to keep a single pointer to the tail: then tail->next is the head, giving O(1) access to both ends.

struct Node {
    int data;
    Node* next;
    Node(int v) : data(v), next(nullptr) {}
};
// A single node points to itself:  n->next == n

Traverse safely with a do-while pattern

You cannot loop “until null” — there is no null. Instead, remember where you started and stop when you return to it. A do-while style visits each node exactly once.

void printCircular(Node* head) {
    if (head == nullptr) return;
    Node* cur = head;
    do {
        std::cout << cur->data << " ";
        cur = cur->next;
    } while (cur != head);
}

Insert at the front (tail-pointer design)

Holding the tail, the head is tail->next. To push a new node to the front, splice it between the tail and the old head — the tail itself does not move.

Node* pushFront(Node* tail, int value) {
    Node* node = new Node(value);
    if (tail == nullptr) {        // empty list
        node->next = node;        // points to itself
        return node;              // node is the only node, also the tail
    }
    node->next = tail->next;      // new node -> old head
    tail->next = node;            // tail -> new head
    return tail;                  // tail is unchanged
}

Going deeper: With this tail-pointer design, push-back is identical to push-front but you also advance the tail to the new node (return node instead of return tail). That gives O(1) insertion at both ends with a single stored pointer.

Complexity

OperationTime
Insert at front (tail pointer)O(1)
Insert at back (tail pointer)O(1)
Access head / tailO(1)
Search / access by indexO(n)

Pitfall: The number-one circular-list bug is an infinite loop — looping “until next is null” never terminates. Always anchor on the start node and stop when you come back to it. Handle the empty and single-node (self-pointing) cases explicitly.

When to use a circular linked list

Pick a circular linked list whenever processing should wrap around forever: round-robin CPU scheduling, turn-taking in a game, a repeating media playlist, or a ring buffer. If you never need to wrap, a plain singly or doubly list is simpler and less error-prone.

Next: tie it all together with the core linked list operations, then learn reversing a linked list.

Last updated June 25, 2026
Was this helpful?