Back to Data Structures & Algorithms
2026-03-257 min read

circular linked list and operations on it. (Data Structures & Algorithms)

Learn circular linked list and operations on it. (Data Structures & Algorithms) step by step with clear examples and exercises.

Why This Matters

Circular Linked Lists are a crucial variation of traditional linked lists, offering several advantages:

  1. Efficient implementation of cyclic data structures such as queues and stacks without wasting memory by allocating a fixed size.
  2. Simulating computer systems with memory cycles, where the program counter points to the next instruction.
  3. Debugging memory leaks in linked lists during testing by creating circular references intentionally.
  4. Demonstrating knowledge of data structures and algorithms in interviews and exams.
  5. Understanding circular linked lists provides a foundation for more complex data structures like doubly-linked lists, cyclic graphs, and self-organizing lists.

Prerequisites

To follow this lesson, you should be familiar with the following:

  1. Basic Python syntax (variables, functions, loops, and conditionals)
  2. Understanding of linked lists and their operations
  3. Familiarity with data structures and algorithms concepts
  4. Knowledge of common Python libraries like collections for deque implementation

Core Concept

Definition and Representation

A circular linked list is a linear collection of nodes where the last node points back to the first node, forming a loop. Each node consists of two parts: data and a reference (link) to the next node. In a circular linked list, the last node's link points back to the head node.

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

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

Insertion Operations

  1. Insert at the beginning (prepend): Add a new node at the start of the circular linked list, updating the head and tail if necessary.
def prepend(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
self.tail = new_node
else:
new_node.next = self.head
self.tail.next = new_node
self.tail = new_node
  1. Insert at the end (append): Add a new node at the end of the circular linked list, updating the head and tail if necessary.
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
self.tail = new_node
else:
current = self.head
while current.next != self.head:
current = current.next
current.next = new_node
self.tail = new_node
  1. Insert at a specific position: Insert a new node after the given position in the circular linked list, updating the head and tail if necessary.
def insert_at(self, data, position):
if not self.head:
self.head = Node(data)
self.tail = self.head
return

new_node = Node(data)

if position <= 0:
new_node.next = self.head
self.head = new_node
self.tail.next = new_node
self.tail = new_node
else:
current = self.head
for _ in range(position - 1):
if not current.next:
raise IndexError("Position out of range")
current = current.next
new_node.next = current.next
current.next = new_node

Deletion Operations

  1. Delete from the beginning (remove first): Remove the first node in the circular linked list and return its data. Update the head if necessary.
def remove_first(self):
if not self.head:
return None

data = self.head.data

if self.head == self.tail:
self.head = None
self.tail = None
else:
current = self.head
while current.next != self.head:
current = current.next
current.next = self.head.next
self.head = self.head.next

return data
  1. Delete from the end (remove last): Remove the last node in the circular linked list and return its data. Update the tail if necessary.
def remove_last(self):
if not self.head:
return None

if self.head == self.tail:
data = self.head.data
self.head = None
self.tail = None
return data

current = self.head
while current.next != self.tail:
current = current.next
data = self.tail.data
self.tail = current
self.tail.next = self.head

if not self.head:
self.tail = None

return data
  1. Delete a node at a specific position: Remove the node at the given position in the circular linked list and return its data. Update the head and tail if necessary.
def delete_at(self, position):
if not self.head:
raise IndexError("List is empty")

if position <= 0:
data = self.remove_first()
else:
current = self.head
for _ in range(position - 1):
if not current.next:
raise IndexError("Position out of range")
current = current.next

data = current.next.data
current.next = current.next.next

if self.head == self.tail and not self.head:
self.head = None
self.tail = None
elif self.tail == current:
self.tail = current

return data

Worked Example

Let's create a circular linked list, insert nodes, and perform various operations.

my_list = CircularLinkedList()
my_list.prepend(1)
my_list.append(2)
my_list.append(3)
print("Original List: ", end=" ")
current = my_list.head
while current != None:
print(current.data, end=" ")
current = current.next
print()

Remove first node

removed_data = my_list.remove_first()

if removed_data:

print("Removed first:", removed_data)

current = my_list.head

while current != None:

print(current.data, end=" ")

current = current.next

print()

Remove last node

removed_data = my_list.remove_last()

if removed_data:

print("Removed last:", removed_data)

current = my_list.head

while current != None:

print(current.data, end=" ")

current = current.next

print()

Insert a node at position 2

my_list.insert_at(4, 2)

print("Inserted at position 2:", end=" ")

current = my_list.head

while current != None:

print(current.data, end=" ")

current = current.next

print()

Delete a node at position 1

removed_data = my_list.delete_at(1)

if removed_data:

print("Deleted at position 1:", removed_data)

current = my_list.head

while current != None:

print(current.data, end=" ")

current = current.next

print()


Output:

Original List: 1 2 3

Removed first: 1

Original List: 2 3 1

Removed last: 3

Original List: 2 1

Inserted at position 2: 4 2 1

Deleted at position 1: 2

Original List: 4 1

Common Mistakes

  1. Forgetting to update the tail when inserting or deleting nodes.
  2. Not handling the edge case where the circular linked list is empty during insertion and deletion operations.
  3. Using a regular linked list instead of a circular one, causing incorrect results for cyclic data structures like queues and stacks.
  4. Failing to traverse the entire circular linked list when performing operations like finding the length or printing all nodes.
  5. Not properly handling out-of-range errors during insertion and deletion at specific positions.
  6. Incorrectly implementing the insert_at(), delete_at() methods, resulting in memory leaks or incorrect data removal.

Practice Questions

  1. Implement a method to find the length of a circular linked list.
  2. Implement a method to search for a value in a circular linked list.
  3. Implement a method to reverse the order of nodes in a circular linked list.
  4. Implement a circular queue using the circular linked list data structure.
  5. Implement a method to merge two circular linked lists.
  6. Implement a method to find the kth node from the end of a circular linked list.
  7. Implement a method to detect if a circular linked list has a cycle (self-intersection).
  8. Implement a method to remove duplicates from a circular linked list.
  9. Implement a method to sort a circular linked list in ascending order.
  10. Implement a method to sort a circular linked list in descending order.

FAQ

What is the advantage of using a circular linked list over a regular linked list?

  • A circular linked list allows for efficient implementation of cyclic data structures such as queues and stacks without wasting memory by allocating a fixed size. It also simplifies certain algorithms like detecting cycles in graphs.

How do I traverse a circular linked list to print all nodes?

  • To traverse a circular linked list, start from the head node and keep following the next pointer until you reach the initial node again. Alternatively, you can use two pointers: one moves one step ahead while the other moves two steps ahead, meeting at the cycle's beginning or end if it exists.

What is the time complexity of inserting and deleting nodes in a circular linked list?

  • Inserting and deleting nodes in a circular linked list have an average time complexity of O(1), as they require constant time regardless of the size of the list. However, finding the position to insert or delete a node has a time complexity of O(n) in the worst case when the list is full.

How can I find the middle node of a circular linked list?

  • To find the middle node of a circular linked list, start from the head node and traverse at half the length of the list (rounded down). Stop when you reach the next node after the current one. The current node is the middle node if the list has an even number of nodes, or the next node is the middle node if the list has an odd number of nodes.

What happens if I create a circular linked list with only one node?

  • A circular linked list with only one node is still considered a circular linked list, as the node points back to itself forming a loop. This single-node circular linked list can be used for various purposes like representing an empty cyclic data structure or a special case in certain algorithms.
circular linked list and operations on it. (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn