Data Structures and Algorithms
- Introduction to Data Structures and Algorithms
- Time and Space Complexity Analysis
- Big-O, Big-Theta, and Big-Omega Notations
- Recursion and Backtracking
- Divide and Conquer Algorithm
- Dynamic Programming: Memoization vs. Tabulation
- Greedy Algorithms and Their Use Cases
- Understanding Arrays: Types and Operations
- Linear Search vs. Binary Search
- Sorting Algorithms: Bubble, Insertion, Selection, and Merge Sort
- QuickSort: Explanation and Implementation
- Heap Sort and Its Applications
- Counting Sort, Radix Sort, and Bucket Sort
- Hashing Techniques: Hash Tables and Collisions
- Open Addressing vs. Separate Chaining in Hashing
- DSA Questions for Beginners
- Advanced DSA Questions for Competitive Programming
- Top 10 DSA Questions to Crack Your Next Coding Test
- Top 50 DSA Questions Every Programmer Should Practice
- Top Atlassian DSA Interview Questions
- Top Amazon DSA Interview Questions
- Top Microsoft DSA Interview Questions
- Top Meta (Facebook) DSA Interview Questions
- Netflix DSA Interview Questions and Preparation Guide
- Top 20 DSA Interview Questions You Need to Know
- Top Uber DSA Interview Questions and Solutions
- Google DSA Interview Questions and How to Prepare
- Airbnb DSA Interview Questions and How to Solve Them
- Mobile App DSA Interview Questions and Solutions
DSA Interview Questions
- DSA Questions for Beginners
- Advanced DSA Questions for Competitive Programming
- Top 10 DSA Questions to Crack Your Next Coding Test
- Top 50 DSA Questions Every Programmer Should Practice
- Top Atlassian DSA Interview Questions
- Top Amazon DSA Interview Questions
- Top Microsoft DSA Interview Questions
- Top Meta (Facebook) DSA Interview Questions
- Netflix DSA Interview Questions and Preparation Guide
- Top 20 DSA Interview Questions You Need to Know
- Top Uber DSA Interview Questions and Solutions
- Google DSA Interview Questions and How to Prepare
- Airbnb DSA Interview Questions and How to Solve Them
- Mobile App DSA Interview Questions and Solutions
Introduction to High-Level System Design
System Design Fundamentals
- Functional vs. Non-Functional Requirements
- Scalability, Availability, and Reliability
- Latency and Throughput Considerations
- Load Balancing Strategies
Architectural Patterns
- Monolithic vs. Microservices Architecture
- Layered Architecture
- Event-Driven Architecture
- Serverless Architecture
- Model-View-Controller (MVC) Pattern
- CQRS (Command Query Responsibility Segregation)
Scaling Strategies
- Vertical Scaling vs. Horizontal Scaling
- Sharding and Partitioning
- Data Replication and Consistency Models
- Load Balancing Strategies
- CDN and Edge Computing
Database Design in HLD
- SQL vs. NoSQL Databases
- CAP Theorem and its Impact on System Design
- Database Indexing and Query Optimization
- Database Sharding and Partitioning
- Replication Strategies
API Design and Communication
Caching Strategies
- Types of Caching
- Cache Invalidation Strategies
- Redis vs. Memcached
- Cache-Aside, Write-Through, and Write-Behind Strategies
Message Queues and Event-Driven Systems
- Kafka vs. RabbitMQ vs. SQS
- Pub-Sub vs. Point-to-Point Messaging
- Handling Asynchronous Workloads
- Eventual Consistency in Distributed Systems
Security in System Design
Observability and Monitoring
- Logging Strategies (ELK Stack, Prometheus, Grafana)
- API Security Best Practices
- Secure Data Storage and Access Control
- DDoS Protection and Rate Limiting
Real-World System Design Case Studies
- Distributed locking (Locking and its Types)
- Memory leaks and Out of memory issues
- HLD of YouTube
- HLD of WhatsApp
System Design Interview Questions
- Adobe System Design Interview Questions
- Top Atlassian System Design Interview Questions
- Top Amazon System Design Interview Questions
- Top Microsoft System Design Interview Questions
- Top Meta (Facebook) System Design Interview Questions
- Top Netflix System Design Interview Questions
- Top Uber System Design Interview Questions
- Top Google System Design Interview Questions
- Top Apple System Design Interview Questions
- Top Airbnb System Design Interview Questions
- Top 10 System Design Interview Questions
- Mobile App System Design Interview Questions
- Top 20 Stripe System Design Interview Questions
- Top Shopify System Design Interview Questions
- Top 20 System Design Interview Questions
- Top Advanced System Design Questions
- Most-Frequented System Design Questions in Big Tech Interviews
- What Interviewers Look for in System Design Questions
- Critical System Design Questions to Crack Any Tech Interview
- Top 20 API Design Questions for System Design Interviews
- Top 10 Steps to Create a System Design Portfolio for Developers
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.

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.

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.

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

- At the end: Attach a new node after the last one, linking it back to the head.
#include
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

- After a specific node: Insert a node following a given position, adjusting pointers
accordingly.

Deletion
- First node: Remove the head, updating the last node to point to the new head.
#include
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
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
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
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.
What is stack overflow and stack underflow?
- 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.
Can a stack be implemented using queues?
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.
What is the difference between a stack and a queue?
- 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.
Are there any limitations of using a stack?
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
- 85+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests & Quizzes
- Topic-wise Quizzes
- Case Studies
- Access to Global Peer Community
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.

Essentials of Machine Learning and Artificial Intelligence
- 65+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 22+ Hands-on Live Projects & Deployments
- Comprehensive Notes
- Topic-wise Quizzes
- Case Studies
- Access to Global Peer Community
- Interview Prep Material
Buy for 65% OFF
₹20,000.00 ₹6,999.00

Fast-Track to Full Spectrum Software Engineering
- 120+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests & Quizzes
- 12+ live Projects & Deployments
- Case Studies
- Access to Global Peer Community
Buy for 57% OFF
₹35,000.00 ₹14,999.00

DSA, High & Low Level System Designs
- 85+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests & Quizzes
- Topic-wise Quizzes
- Case Studies
- Access to Global Peer Community
Buy for 60% OFF
₹25,000.00 ₹9,999.00

Low & High Level System Design
- 20+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests
- Topic-wise Quizzes
- Access to Global Peer Community
- Interview Prep Material
Buy for 65% OFF
₹20,000.00 ₹6,999.00

Mastering Mern Stack (WEB DEVELOPMENT)
- 65+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 12+ Hands-on Live Projects & Deployments
- Comprehensive Notes & Quizzes
- Real-world Tools & Technologies
- Access to Global Peer Community
- Interview Prep Material
- Placement Assistance
Buy for 60% OFF
₹15,000.00 ₹5,999.00

Mastering Data Structures & Algorithms
- 65+ Live Classes & Recordings
- 24*7 Live Doubt Support
- 400+ DSA Practice Questions
- Comprehensive Notes
- HackerRank Tests
- Access to Global Peer Community
- Topic-wise Quizzes
- Interview Prep Material
Buy for 50% OFF
₹9,999.00 ₹4,999.00
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