Data Structures and Algorithms

Understanding Circular Linked Lists in Data Structures

Linked lists form the backbone of many data structures, connecting nodes with data and pointers to the next in line. Among their intriguing variants, circular linked lists stand out by looping the last node back to the first, creating an endless cycle. This guide dives deep into circular linked lists, covering their types, operations, implementations, and practical uses. Whether you’re preparing for coding interviews or building real-world applications, mastering this structure can give you an edge. Stay ahead of the curve, sign up for our newsletter to unlock free courses and get the latest updates on data structures and more!

What is a Circular Linked List?

A circular linked list transforms the traditional linked list by connecting the last node to the first, forming a continuous loop. Unlike linear linked lists that end with a null pointer, this structure allows traversal to cycle indefinitely from any starting point. This unique trait makes it a powerful tool for tasks requiring repetitive or circular processing, such as scheduling or resource management. 

Curious about other data structures? Explore our DSA course for comprehensive learning.

What is a Circular Linked List?

Types of Circular Linked Lists

Circular linked lists come in two distinct types, each with its own strengths:

Circular Singly Linked List

Here, each node holds data and a pointer to the next node, with the last node linking back to the first. This creates a one-way loop, perfect for simple cyclic operations where forward traversal suffices.

Types of Circular Linked Lists

Circular Doubly Linked List

More complex, this type equips nodes with two pointers: one to the next node and one to the previous. The last node connects to the first, and the first to the last, enabling bidirectional traversal. This flexibility suits advanced applications but demands careful pointer management.

Circular Doubly Linked List

Basic Operations on Circular Linked Lists

Circular linked lists support a range of operations, each tailored to maintain the loop:

Insertion

  • At the beginning: Add a new node as the head, redirecting the last node’s pointer to it. 
				
					class CircularLinkedList {
private:
    struct Node {
        int data;
        Node* next;
        Node(int data) : data(data), next(nullptr) {}
    };
    Node* head;

public:
    CircularLinkedList() : head(nullptr) {}

    void insertAtBeginning(int data) {
        Node* newNode = new Node(data);
        if (head == nullptr) {
            // If the list is empty, make the new node point to itself
            newNode->next = newNode;
            head = newNode;
        } else {
            // Traverse to the last node
            Node* current = head;
            while (current->next != head) {
                current = current->next;
            }
            // Link the last node to the new node, and the new node to the head
            current->next = newNode;
            newNode->next = head;
            // Update head to the new node
            head = newNode;
        }
    }

    // Destructor to free memory
    ~CircularLinkedList() {
        if (head != nullptr) {
            Node* current = head;
            do {
                Node* next = current->next;
                delete current;
                current = next;
            } while (current != head);
        }
    }
};

				
			
				
					public class CircularLinkedList {
    private Node head;

    // Inner Node class to represent each node in the list
    private class Node {
        int data;
        Node next;

        Node(int data) {
            this.data = data;
            this.next = null;
        }
    }

    // Method to insert a new node at the beginning
    public void insertAtBeginning(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            // If the list is empty, make the new node point to itself
            newNode.next = newNode;
            head = newNode;
        } else {
            // Traverse to the last node
            Node current = head;
            while (current.next != head) {
                current = current.next;
            }
            // Link the last node to the new node, and the new node to the head
            current.next = newNode;
            newNode.next = head;
            // Update head to the new node
            head = newNode;
        }
    }
}

				
			
				
					class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

class CircularLinkedList {
    constructor() {
        this.head = null;
    }

    insertAtBeginning(data) {
        const newNode = new Node(data);
        if (!this.head) {
            // If the list is empty, make the new node point to itself
            newNode.next = newNode;
            this.head = newNode;
        } else {
            // Traverse to the last node
            let current = this.head;
            while (current.next !== this.head) {
                current = current.next;
            }
            // Link the last node to the new node, and the new node to the head
            current.next = newNode;
            newNode.next = this.head;
            // Update head to the new node
            this.head = newNode;
        }
    }
}

				
			
				
					def insertAtBeginning(self, data):
        new_node = Node(data)
        if not self.head:
            new_node.next = new_node
            self.head = new_node
        else:
            current = self.head
            while current.next != self.head:
                current = current.next
            current.next = new_node
            new_node.next = self.head
            self.head = new_node

				
			
Insertion
  • At the end: Attach a new node after the last one, linking it back to the head.
				
					#include <iostream>
using namespace std;

struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {}
};

class CircularLinkedList {
private:
    Node* head;

public:
    CircularLinkedList() : head(nullptr) {}

    // Insert at end
    void insertAtEnd(int data) {
        Node* newNode = new Node(data);
        if (head == nullptr) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* current = head;
            // traverse to last node
            while (current->next != head) {
                current = current->next;
            }
            current->next = newNode;
            newNode->next = head;
        }
    }

    // For testing
    void printList() {
        if (!head) return;
        Node* curr = head;
        do {
            cout << curr->data << " ";
            curr = curr->next;
        } while (curr != head);
        cout << endl;
    }
};

int main() {
    CircularLinkedList list;
    list.insertAtEnd(10);
    list.insertAtEnd(20);
    list.insertAtEnd(30);
    list.printList();  // Outputs: 10 20 30
    return 0;
}

				
			
				
					// Node definition
class Node {
    int data;
    Node next;
    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
public class CircularLinkedList {
    private Node head;

    public CircularLinkedList() {
        this.head = null;
    }

    // Insert at end
    public void insertAtEnd(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node current = head;
            // traverse to last node
            while (current.next != head) {
                current = current.next;
            }
            current.next = newNode;
            newNode.next = head;
        }
    }

    // For testing
    public void printList() {
        if (head == null) return;
        Node curr = head;
        do {
            System.out.print(curr.data + " ");
            curr = curr.next;
        } while (curr != head);
        System.out.println();
    }
}

				
			
				
					// Node definition
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
class CircularLinkedList {
    constructor() {
        this.head = null;
    }

    // Insert at end
    insertAtEnd(data) {
        const newNode = new Node(data);
        if (this.head === null) {
            newNode.next = newNode;
            this.head = newNode;
        } else {
            let current = this.head;
            // traverse to last node
            while (current.next !== this.head) {
                current = current.next;
            }
            current.next = newNode;
            newNode.next = this.head;
        }
    }

    // For testing
    printList() {
        if (!this.head) return;
        let curr = this.head;
        const out = [];
        do {
            out.push(curr.data);
            curr = curr.next;
        } while (curr !== this.head);
        console.log(out.join(' '));
    }
}

				
			
				
					 def insertAtEnd(self, data):
        new_node = Node(data)
        if not self.head:
            new_node.next = new_node
            self.head = new_node
        else:
            current = self.head
            while current.next != self.head:
                current = current.next
            current.next = new_node
            new_node.next = self.head

				
			
At the end: Attach a new node after the last one, linking it back to the head.
  • After a specific node: Insert a node following a given position, adjusting pointers
    accordingly.
After a specific node: Insert a node following a given position, adjusting pointers

Deletion

  • First node: Remove the head, updating the last node to point to the new head.
				
					#include <iostream>
using namespace std;

struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {}
};

class CircularLinkedList {
private:
    Node* head;

public:
    CircularLinkedList() : head(nullptr) {}

    // Delete the first node
    void deleteFirst() {
        if (head == nullptr) {
            return;
        }
        // only one node
        if (head->next == head) {
            delete head;
            head = nullptr;
        } else {
            // find last node
            Node* current = head;
            while (current->next != head) {
                current = current->next;
            }
            // bypass old head
            Node* oldHead = head;
            current->next = head->next;
            head = head->next;
            delete oldHead;
        }
    }

    // For testing
    void printList() {
        if (!head) {
            cout << "(empty)" << endl;
            return;
        }
        Node* curr = head;
        do {
            cout << curr->data << " ";
            curr = curr->next;
        } while (curr != head);
        cout << endl;
    }
};

int main() {
    CircularLinkedList list;
    list.insertAtEnd(10);
    list.insertAtEnd(20);
    list.insertAtEnd(30);
    list.printList();    // 10 20 30
    list.deleteFirst();
    list.printList();    // 20 30
    return 0;
}

				
			

Last node: Delete the tail, rerouting the second-to-last node to the head. 

				
					#include <iostream>
using namespace std;

struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {}
};

class CircularLinkedList {
private:
    Node* head;

public:
    CircularLinkedList() : head(nullptr) {}

    // Delete the first node
    void deleteFirst() {
        if (head == nullptr) {
            return;
        }
        // only one node
        if (head->next == head) {
            delete head;
            head = nullptr;
        } else {
            // find last node
            Node* current = head;
            while (current->next != head) {
                current = current->next;
            }
            // bypass old head
            Node* oldHead = head;
            current->next = head->next;
            head = head->next;
            delete oldHead;
        }
    }

    // For testing
    void printList() {
        if (!head) {
            cout << "(empty)" << endl;
            return;
        }
        Node* curr = head;
        do {
            cout << curr->data << " ";
            curr = curr->next;
        } while (curr != head);
        cout << endl;
    }
};

int main() {
    CircularLinkedList list;
    list.insertAtEnd(10);
    list.insertAtEnd(20);
    list.insertAtEnd(30);
    list.printList();    // 10 20 30
    list.deleteFirst();
    list.printList();    // 20 30
    return 0;
}

				
			

Last node: Delete the tail, rerouting the second-to-last node to the head. 

				
					// Node definition
class Node {
    int data;
    Node next;
    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
public class CircularLinkedList {
    private Node head;

    public CircularLinkedList() {
        this.head = null;
    }

    // Delete the first node
    public void deleteFirst() {
        if (head == null) {
            return;
        }
        // only one node
        if (head.next == head) {
            head = null;
        } else {
            // find last node
            Node current = head;
            while (current.next != head) {
                current = current.next;
            }
            // bypass old head
            current.next = head.next;
            head = head.next;
        }
    }

    // For testing
    public void printList() {
        if (head == null) {
            System.out.println("(empty)");
            return;
        }
        Node curr = head;
        do {
            System.out.print(curr.data + " ");
            curr = curr.next;
        } while (curr != head);
        System.out.println();
    }
}

				
			
				
					// Node definition
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
class CircularLinkedList {
    constructor() {
        this.head = null;
    }

    // Delete the first node
    deleteFirst() {
        if (this.head === null) {
            return;
        }
        // only one node
        if (this.head.next === this.head) {
            this.head = null;
        } else {
            // find last node
            let current = this.head;
            while (current.next !== this.head) {
                current = current.next;
            }
            // bypass old head
            current.next = this.head.next;
            this.head = this.head.next;
        }
    }

    // For testing
    printList() {
        if (!this.head) {
            console.log("(empty)");
            return;
        }
        const out = [];
        let curr = this.head;
        do {
            out.push(curr.data);
            curr = curr.next;
        } while (curr !== this.head);
        console.log(out.join(' '));
    }
}

				
			
				
					 # Deletion of the last node
    def deleteLast(self):
        if not self.head:
            return
        if self.head.next == self.head:
            self.head = None
        else:
            current = self.head
            while current.next.next != self.head:
                current = current.next
            current.next = self.head


    # Deletion by value (first occurrence)
    def deleteByValue(self, value):
        if not self.head:
            return
        current = self.head
        prev = None
        found = False
        while True:
            if current.data == value:
                found = True
                break
            prev = current
            current = current.next
            if current == self.head:
                break
        if found:
            if prev is None:  # It's the head
                self.deleteFirst()
            else:
                prev.next = current.next
        else:
            print("Value not found.")

				
			
				
					// Node definition
class Node {
    int data;
    Node next;
    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
public class CircularLinkedList {
    private Node head;

    public CircularLinkedList() {
        this.head = null;
    }

    // Delete the first node
    public void deleteFirst() {
        if (head == null) {
            return;
        }
        // only one node
        if (head.next == head) {
            head = null;
        } else {
            // find last node
            Node current = head;
            while (current.next != head) {
                current = current.next;
            }
            // bypass old head
            current.next = head.next;
            head = head.next;
        }
    }

    // For testing
    public void printList() {
        if (head == null) {
            System.out.println("(empty)");
            return;
        }
        Node curr = head;
        do {
            System.out.print(curr.data + " ");
            curr = curr.next;
        } while (curr != head);
        System.out.println();
    }
}

				
			
				
					// Node definition
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
class CircularLinkedList {
    constructor() {
        this.head = null;
    }

    // Delete the first node
    deleteFirst() {
        if (this.head === null) {
            return;
        }
        // only one node
        if (this.head.next === this.head) {
            this.head = null;
        } else {
            // find last node
            let current = this.head;
            while (current.next !== this.head) {
                current = current.next;
            }
            // bypass old head
            current.next = this.head.next;
            this.head = this.head.next;
        }
    }

    // For testing
    printList() {
        if (!this.head) {
            console.log("(empty)");
            return;
        }
        const out = [];
        let curr = this.head;
        do {
            out.push(curr.data);
            curr = curr.next;
        } while (curr !== this.head);
        console.log(out.join(' '));
    }
}

				
			
				
					# Deletion of the first node
    def deleteFirst(self):
        if not self.head:
            return
        if self.head.next == self.head:
            self.head = None
        else:
            current = self.head
            while current.next != self.head:
                current = current.next
            current.next = self.head.next
            self.head = self.head.next

				
			

Specific node:
Excise a chosen node, reconnecting its neighbors.

Traversal

Start at any node and cycle through the list, returning to the starting point—a key feature for repetitive tasks.

				
					#include <iostream>
using namespace std;

struct Node {
    int data;
    Node* next;
    Node(int val) : data(val), next(nullptr) {}
};

class CircularLinkedList {
private:
    Node* head;

public:
    CircularLinkedList() : head(nullptr) {}

    // 1. Insert at beginning
    void insertAtBeginning(int data) {
        Node* newNode = new Node(data);
        if (!head) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* curr = head;
            while (curr->next != head) {
                curr = curr->next;
            }
            curr->next = newNode;
            newNode->next = head;
            head = newNode;
        }
    }

    // 2. Insert at end
    void insertAtEnd(int data) {
        Node* newNode = new Node(data);
        if (!head) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* curr = head;
            while (curr->next != head) {
                curr = curr->next;
            }
            curr->next = newNode;
            newNode->next = head;
        }
    }

    // 3. Delete first node
    void deleteFirst() {
        if (!head) return;
        if (head->next == head) {
            delete head;
            head = nullptr;
        } else {
            Node* curr = head;
            while (curr->next != head) {
                curr = curr->next;
            }
            Node* oldHead = head;
            curr->next = head->next;
            head = head->next;
            delete oldHead;
        }
    }

    // 4. Delete last node
    void deleteLast() {
        if (!head) return;
        if (head->next == head) {
            delete head;
            head = nullptr;
        } else {
            Node* curr = head;
            while (curr->next->next != head) {
                curr = curr->next;
            }
            delete curr->next;
            curr->next = head;
        }
    }

    // 5. Delete by value (first occurrence)
    void deleteByValue(int value) {
        if (!head) return;
        Node* curr = head;
        Node* prev = nullptr;
        bool found = false;
        do {
            if (curr->data == value) {
                found = true;
                break;
            }
            prev = curr;
            curr = curr->next;
        } while (curr != head);

        if (!found) {
            cout << "Value not found." << endl;
            return;
        }
        if (prev == nullptr) {
            deleteFirst();
        } else {
            prev->next = curr->next;
            delete curr;
        }
    }

    // 6. Display / traverse
    void displayList() {
        if (!head) {
            cout << "List is empty." << endl;
            return;
        }
        Node* curr = head;
        do {
            cout << curr->data << " -> ";
            curr = curr->next;
        } while (curr != head);
        cout << "(head)" << endl;
    }
};

// Example usage
int main() {
    CircularLinkedList cll;
    cll.insertAtBeginning(10);
    cll.insertAtBeginning(20);
    cll.insertAtEnd(30);
    cll.insertAtEnd(40);
    cll.displayList();  // 20 -> 10 -> 30 -> 40 -> (head)

    cll.deleteFirst();
    cll.displayList();  // 10 -> 30 -> 40 -> (head)

    cll.deleteLast();
    cll.displayList();  // 10 -> 30 -> (head)

    cll.deleteByValue(30);
    cll.displayList();  // 10 -> (head)

    return 0;
}

				
			

Searching

Traverse the loop to find a target value, requiring safeguards against infinite loops.

For a quick refresher on these operations, try our crash course.

Implementation of Circular Linked Lists

Let’s see how circular linked lists come to life in code. Below are examples in C, C++, and Java for inserting nodes at the beginning and end.

				
					// Node definition
class Node {
    int data;
    Node next;
    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
public class CircularLinkedList {
    private Node head;

    public CircularLinkedList() {
        this.head = null;
    }

    // 1. Insert at beginning
    public void insertAtBeginning(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node curr = head;
            while (curr.next != head) {
                curr = curr.next;
            }
            curr.next = newNode;
            newNode.next = head;
            head = newNode;
        }
    }

    // 2. Insert at end
    public void insertAtEnd(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node curr = head;
            while (curr.next != head) {
                curr = curr.next;
            }
            curr.next = newNode;
            newNode.next = head;
        }
    }

    // 3. Delete first node
    public void deleteFirst() {
        if (head == null) return;
        if (head.next == head) {
            head = null;
        } else {
            Node curr = head;
            while (curr.next != head) {
                curr = curr.next;
            }
            curr.next = head.next;
            head = head.next;
        }
    }

    // 4. Delete last node
    public void deleteLast() {
        if (head == null) return;
        if (head.next == head) {
            head = null;
        } else {
            Node curr = head;
            while (curr.next.next != head) {
                curr = curr.next;
            }
            curr.next = head;
        }
    }

    // 5. Delete by value (first occurrence)
    public void deleteByValue(int value) {
        if (head == null) return;
        Node curr = head, prev = null;
        boolean found = false;
        do {
            if (curr.data == value) {
                found = true;
                break;
            }
            prev = curr;
            curr = curr.next;
        } while (curr != head);

        if (!found) {
            System.out.println("Value not found.");
            return;
        }
        if (prev == null) {
            deleteFirst();
        } else {
            prev.next = curr.next;
        }
    }

    // 6. Display / traverse
    public void displayList() {
        if (head == null) {
            System.out.println("List is empty.");
            return;
        }
        Node curr = head;
        do {
            System.out.print(curr.data + " -> ");
            curr = curr.next;
        } while (curr != head);
        System.out.println("(head)");
    }

    // Example usage
    public static void main(String[] args) {
        CircularLinkedList cll = new CircularLinkedList();
        cll.insertAtBeginning(10);
        cll.insertAtBeginning(20);
        cll.insertAtEnd(30);
        cll.insertAtEnd(40);
        cll.displayList();  // 20 -> 10 -> 30 -> 40 -> (head)

        cll.deleteFirst();
        cll.displayList();  // 10 -> 30 -> 40 -> (head)

        cll.deleteLast();
        cll.displayList();  // 10 -> 30 -> (head)

        cll.deleteByValue(30);
        cll.displayList();  // 10 -> (head)
    }
}

				
			
				
					// Node definition
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

// Circular linked list
class CircularLinkedList {
    constructor() {
        this.head = null;
    }

    // 1. Insert at beginning
    insertAtBeginning(data) {
        const newNode = new Node(data);
        if (!this.head) {
            newNode.next = newNode;
            this.head = newNode;
        } else {
            let curr = this.head;
            while (curr.next !== this.head) {
                curr = curr.next;
            }
            curr.next = newNode;
            newNode.next = this.head;
            this.head = newNode;
        }
    }

    // 2. Insert at end
    insertAtEnd(data) {
        const newNode = new Node(data);
        if (!this.head) {
            newNode.next = newNode;
            this.head = newNode;
        } else {
            let curr = this.head;
            while (curr.next !== this.head) {
                curr = curr.next;
            }
            curr.next = newNode;
            newNode.next = this.head;
        }
    }

    // 3. Delete first node
    deleteFirst() {
        if (!this.head) return;
        if (this.head.next === this.head) {
            this.head = null;
        } else {
            let curr = this.head;
            while (curr.next !== this.head) {
                curr = curr.next;
            }
            curr.next = this.head.next;
            this.head = this.head.next;
        }
    }

    // 4. Delete last node
    deleteLast() {
        if (!this.head) return;
        if (this.head.next === this.head) {
            this.head = null;
        } else {
            let curr = this.head;
            while (curr.next.next !== this.head) {
                curr = curr.next;
            }
            curr.next = this.head;
        }
    }

    // 5. Delete by value (first occurrence)
    deleteByValue(value) {
        if (!this.head) return;
        let curr = this.head, prev = null, found = false;
        do {
            if (curr.data === value) {
                found = true;
                break;
            }
            prev = curr;
            curr = curr.next;
        } while (curr !== this.head);

        if (!found) {
            console.log("Value not found.");
            return;
        }
        if (prev === null) {
            this.deleteFirst();
        } else {
            prev.next = curr.next;
        }
    }

    // 6. Display / traverse
    displayList() {
        if (!this.head) {
            console.log("List is empty.");
            return;
        }
        let curr = this.head, out = "";
        do {
            out += curr.data + " -> ";
            curr = curr.next;
        } while (curr !== this.head);
        console.log(out + "(head)");
    }
}

// Example usage
const cll = new CircularLinkedList();
cll.insertAtBeginning(10);
cll.insertAtBeginning(20);
cll.insertAtEnd(30);
cll.insertAtEnd(40);
cll.displayList();  // 20 -> 10 -> 30 -> 40 -> (head)

cll.deleteFirst();
cll.displayList();  // 10 -> 30 -> 40 -> (head)

cll.deleteLast();
cll.displayList();  // 10 -> 30 -> (head)

cll.deleteByValue(30);
cll.displayList();  // 10 -> (head)

				
			
				
					 # Traversal and display
    def displayList(self):
        if not self.head:
            print("List is empty.")
            return
        current = self.head
        print(current.data, end=" -> ")
        current = current.next
        while current != self.head:
            print(current.data, end=" -> ")
            current = current.next
        print("(head)")


# Example usage
if __name__ == "__main__":
    cll = CircularLinkedList()
    cll.insertAtBeginning(10)
    cll.insertAtBeginning(20)
    cll.insertAtEnd(30)
    cll.insertAtEnd(40)
    cll.displayList()  # Output: 20 -> 10 -> 30 -> 40 -> (head)


    cll.deleteFirst()
    cll.displayList()  # Output: 10 -> 30 -> 40 -> (head)


    cll.deleteLast()
    cll.displayList()  # Output: 10 -> 30 -> (head)


    cll.deleteByValue(30)
    cll.displayList()  # Output: 10 -> (head)

				
			
				
					#include <iostream>
using namespace std;

class CircularLinkedList {
public:
    struct Node {
        int data;
        Node* next;
    };
    Node* head;

    CircularLinkedList() { head = nullptr; }

    void insertAtBeginning(int data) {
        Node* newNode = new Node();
        newNode->data = data;
        if (!head) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* temp = head;
            while (temp->next != head) temp = temp->next;
            temp->next = newNode;
            newNode->next = head;
            head = newNode;
        }
    }

    void insertAtEnd(int data) {
        Node* newNode = new Node();
        newNode->data = data;
        if (!head) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* temp = head;
            while (temp->next != head) temp = temp->next;
            temp->next = newNode;
            newNode->next = head;
        }
    }

    void displayList() {
        if (!head) {
            cout << "List is empty.\n";
            return;
        }
        Node* temp = head;
        do {
            cout << temp->data << " -> ";
            temp = temp->next;
        } while (temp != head);
        cout << "(head)" << endl;
    }
};

int main() {
    CircularLinkedList cll;
    cll.insertAtBeginning(10);
    cll.insertAtBeginning(20);
    cll.insertAtEnd(30);
    cll.insertAtEnd(40);
    cll.displayList();
    return 0;
}


				
			

Searching

Traverse the loop to find a target value, requiring safeguards against infinite loops.

For a quick refresher on these operations, try our crash course.

Implementation of Circular Linked Lists

Let’s see how circular linked lists come to life in code. Below are examples in C, C++, and Java for inserting nodes at the beginning and end.

				
					class CircularLinkedList {
    static class Node {
        int data;
        Node next;
        Node(int data) {
            this.data = data;
            this.next = null;
        }
    }

    private Node head = null;

    public void insertAtBeginning(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node temp = head;
            while (temp.next != head) temp = temp.next;
            temp.next = newNode;
            newNode.next = head;
            head = newNode;
        }
    }

    public void insertAtEnd(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node temp = head;
            while (temp.next != head) temp = temp.next;
            temp.next = newNode;
            newNode.next = head;
        }
    }

    public void displayList() {
        if (head == null) {
            System.out.println("List is empty.");
            return;
        }
        Node temp = head;
        do {
            System.out.print(temp.data + " -> ");
            temp = temp.next;
        } while (temp != head);
        System.out.println("(head)");
    }

    public static void main(String[] args) {
        CircularLinkedList cll = new CircularLinkedList();
        cll.insertAtBeginning(10);
        cll.insertAtBeginning(20);
        cll.insertAtEnd(30);
        cll.insertAtEnd(40);
        cll.displayList();
    }
}

				
			
				
					class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

class CircularLinkedList {
    constructor() {
        this.head = null;
    }

    insertAtBeginning(data) {
        const newNode = new Node(data);
        if (!this.head) {
            newNode.next = newNode;
            this.head = newNode;
        } else {
            let current = this.head;
            while (current.next !== this.head) {
                current = current.next;
            }
            current.next = newNode;
            newNode.next = this.head;
            this.head = newNode;
        }
    }

    insertAtEnd(data) {
        const newNode = new Node(data);
        if (!this.head) {
            newNode.next = newNode;
            this.head = newNode;
        } else {
            let current = this.head;
            while (current.next !== this.head) {
                current = current.next;
            }
            current.next = newNode;
            newNode.next = this.head;
        }
    }

    displayList() {
        if (!this.head) {
            console.log("List is empty.");
            return;
        }
        let current = this.head;
        let output = "";
        do {
            output += current.data + " -> ";
            current = current.next;
        } while (current !== this.head);
        output += "(head)";
        console.log(output);
    }
}

// Example usage
const cll = new CircularLinkedList();
cll.insertAtBeginning(10);
cll.insertAtBeginning(20);
cll.insertAtEnd(30);
cll.insertAtEnd(40);
cll.displayList();  // Output: 20 -> 10 -> 30 -> 40 -> (head)

Need help with coding interviews? Check out our Top 20 DSA Interview Questions for practice.
				
			
				
					class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class CircularLinkedList:
    def __init__(self):
        self.head = None

    def insertAtBeginning(self, data):
        new_node = Node(data)
        if self.head is None:
            new_node.next = new_node
            self.head = new_node
        else:
            current = self.head
            while current.next != self.head:
                current = current.next
            current.next = new_node
            new_node.next = self.head
            self.head = new_node

    def insertAtEnd(self, data):
        new_node = Node(data)
        if self.head is None:
            new_node.next = new_node
            self.head = new_node
        else:
            current = self.head
            while current.next != self.head:
                current = current.next
            current.next = new_node
            new_node.next = self.head

    def displayList(self):
        if self.head is None:
            print("List is empty.")
            return
        current = self.head
        print(current.data, end=" -> ")
        current = current.next
        while current != self.head:
            print(current.data, end=" -> ")
            current = current.next
        print("(head)")

# Example usage
if __name__ == "__main__":
    cll = CircularLinkedList()
    cll.insertAtBeginning(10)
    cll.insertAtBeginning(20)
    cll.insertAtEnd(30)
    cll.insertAtEnd(40)
    cll.displayList()  # Output: 20 -> 10 -> 30 -> 40 -> (head)

				
			

Advantages and Disadvantages of Circular Linked Lists

Advantages

  • Seamless cycling: No null terminator means endless traversal from any node.
  • Efficient operations: Insertion and deletion are streamlined due to the loop.
  • Algorithm-friendly: Ideal for round-robin scheduling and Fibonacci heaps.
  • Memory optimization: Great for systems reusing resources cyclically.

Disadvantages

  • Complexity: Managing the loop adds overhead compared to linear lists.
  • Infinite loop risk: Requires careful coding to avoid endless cycles.
  • Reversal difficulty: Flipping the list’s direction is trickier.
  • No random access: You must traverse to reach a specific node.

Applications of Circular Linked Lists

Circular linked lists shine in diverse scenarios:

Round-Robin Scheduling

Operating systems use them for round-robin scheduling, cycling through processes with equal time slots. Learn more in our Master DSA & Web Dev course.

Memory Management

They manage memory blocks in a loop, enhancing allocation efficiency in constrained systems.

Game Development

In games, they handle player turns or cyclic events, as seen in our Web Development course.

Data Buffering

Networking apps use them for circular buffers, recycling space for streaming data. See how in our Data Science course.

For more applications, explore our Essential DSA Web Dev Courses.

Conclusion

Circular linked lists blend flexibility with functionality, excelling in cyclic tasks from scheduling to gaming. While they demand precise handling to avoid pitfalls like infinite loops, their benefits—efficient operations and memory use—make them invaluable. Boost your skills with our resources, like the Top Amazon DSA Questions or Top Meta DSA Questions, and stay competitive in tech.

Frequently Asked Questions

How is a stack implemented in programming?

Stacks can be implemented using arrays or linked lists. Array-based stacks have a fixed size, while linked list-based stacks can grow dynamically. For hands-on practice, our DSA course provides step-by-step coding exercises.

  • Stack Overflow: Occurs when trying to push an element onto a full stack.
  • Stack Underflow: Occurs when trying to pop an element from an empty stack.

Master error handling techniques with our web development course.

Yes, but it requires two queues to simulate the LIFO behavior of a stack. This advanced technique is explored in our master DSA and system design course.

  • Stack: Follows LIFO (Last In, First Out).
  • Queue: Follows FIFO (First In, First Out).

Dive into this comparison and more in our master DSA and web dev course.

Yes, stacks only allow access to the top element, which can be restrictive for certain applications. They also risk overflow and underflow if not managed properly. Learn to navigate these trade-offs in our data science course.

Preparing for a big interview? Check out our curated list of top 20 DSA interview questions or explore company-specific guides like Netflix, Meta, Amazon, or Atlassian to get a competitive edge.

DSA, High & Low Level System Designs

Buy for 60% OFF
₹25,000.00 ₹9,999.00

Accelerate your Path to a Product based Career

Boost your career or get hired at top product-based companies by joining our expertly crafted courses. Gain practical skills and real-world knowledge to help you succeed.

Reach Out Now

If you have any queries, please fill out this form. We will surely reach out to you.

Contact Email

Reach us at the following email address.

arun@getsdeready.com

Phone Number

You can reach us by phone as well.

+91-97737 28034

Our Location

Rohini, Sector-3, Delhi-110085

WhatsApp Icon

Master Your Interviews with Our Free Roadmap!

Hi Instagram Fam!
Get a FREE Cheat Sheet on System Design.

Hi LinkedIn Fam!
Get a FREE Cheat Sheet on System Design

Loved Our YouTube Videos? Get a FREE Cheat Sheet on System Design.