What is a Circular Linked List?
A circular linked list is a variation of a linked list where:
- The last node points back to the first node, forming a loop.
- Traversal can continue indefinitely because there’s no
nullat the end.
Circular linked lists can be:
-
Singly Circular: Each node has one pointer (
Next), and the last node points to the head. -
Doubly Circular: Each node has two pointers (
NextandPrev), and the last node’sNextpoints to the head, while the head’sPrevpoints to the last node.
This structure is efficient for situations requiring cyclic traversal, like buffering or real-time simulations.
The Technical View
-
Time Complexity:
- Access: (O(n)) (you must traverse the list).
- Insertion/Deletion:
- At the head or tail: (O(1)).
- At a specific position: (O(n)).
-
Space Complexity:
- (O(n)), where (n) is the number of nodes.
A Fifth-Grader's Summary
Imagine a group of kids playing a game of tag in a circle. Each kid points to the next one in the circle, and there’s no "end" of the line—they just keep going around. That’s how a circular linked list works!
Real-World Example
A carousel (merry-go-round) is a real-world analogy for a circular linked list. Each seat (node) points to the next, and the last seat connects back to the first, creating a continuous loop.
Operations on a Circular Linked List
1. Insert a Node at the Head
Problem: Add a new node with value 3 at the beginning of the list.
Code:
class CircularLinkedListNode {
public int Data;
public CircularLinkedListNode Next;
public CircularLinkedListNode(int data) {
Data = data;
Next = null;
}
}
CircularLinkedListNode InsertAtHead(CircularLinkedListNode head, int data) {
CircularLinkedListNode newNode = new CircularLinkedListNode(data);
if (head == null) {
newNode.Next = newNode;
return newNode;
}
CircularLinkedListNode current = head;
while (current.Next != head) {
current = current.Next;
}
newNode.Next = head;
current.Next = newNode;
return newNode;
}
Initial List: 5 -> 10 -> 15 -> (points back to 5)
Steps:
- Create a new node with data
3. - Traverse to the last node (
15) that points back to the head (5). - Point the last node’s
Nextto the new node. - Point the new node’s
Nextto the current head (5). - Update the head to the new node.
Updated List: 3 -> 5 -> 10 -> 15 -> (points back to 3)
2. Insert a Node at the Tail
Problem: Add a new node with value 20 at the end of the list.
Code:
CircularLinkedListNode InsertAtTail(CircularLinkedListNode head, int data) {
CircularLinkedListNode newNode = new CircularLinkedListNode(data);
if (head == null) {
newNode.Next = newNode;
return newNode;
}
CircularLinkedListNode current = head;
while (current.Next != head) {
current = current.Next;
}
current.Next = newNode;
newNode.Next = head;
return head;
}
Initial List: 5 -> 10 -> 15 -> (points back to 5)
Steps:
- Create a new node with data
20. - Traverse to the last node (
15) that points back to the head (5). - Point the last node’s
Nextto the new node. - Point the new node’s
Nextto the head.
Updated List: 5 -> 10 -> 15 -> 20 -> (points back to 5)
3. Insert a Node at a Specific Position
Problem: Insert a node with value 12 at position 2 (0-based index).
Code:
CircularLinkedListNode InsertAtPosition(CircularLinkedListNode head, int data, int position) {
CircularLinkedListNode newNode = new CircularLinkedListNode(data);
if (position == 0) {
return InsertAtHead(head, data);
}
CircularLinkedListNode current = head;
while (position - 1 > 0) {
current = current.Next;
position--;
}
newNode.Next = current.Next;
current.Next = newNode;
return head;
}
Initial List: 5 -> 10 -> 15 -> (points back to 5)
Steps:
- Create a new node with data
12. - Traverse to the node at position
1(10). - Set the new node’s
Nextto the node at position2(15). - Set the
Nextof the node at position1(10) to the new node.
Updated List: 5 -> 10 -> 12 -> 15 -> (points back to 5)
4. Delete a Node
Problem: Remove the node at position 1 (0-based index).
Code:
CircularLinkedListNode DeleteNode(CircularLinkedListNode head, int position) {
if (head == null) return null;
if (position == 0) {
if (head.Next == head) return null;
CircularLinkedListNode current = head;
while (current.Next != head) {
current = current.Next;
}
current.Next = head.Next;
return current.Next;
}
CircularLinkedListNode currentNode = head;
while (position - 1 > 0) {
currentNode = currentNode.Next;
position--;
}
currentNode.Next = currentNode.Next.Next;
return head;
}
Initial List: 5 -> 10 -> 15 -> (points back to 5)
Steps:
- Traverse to the node at position
0(5). - Update pointers:
- Point
5’sNextto15.
- Point
Updated List: 5 -> 15 -> (points back to 5)
5. Detect a Loop in a Circular Linked List
Problem: Check if the linked list contains a loop.
Code:
bool HasLoop(CircularLinkedListNode head) {
if (head == null) return false;
CircularLinkedListNode slow = head, fast = head;
while (fast != null && fast.Next != null) {
slow = slow.Next;
fast = fast.Next.Next;
if (slow == fast) return true;
}
return false;
}
Initial List: 5 -> 10 -> 15 -> (points back to 5)
Steps:
- Use two pointers (
slowandfast). - Move
slowone step at a time andfasttwo steps. - If they meet, there’s a loop.
Result: Returns true for a circular linked list.
Conclusion
Circular linked lists are useful for scenarios requiring continuous or cyclic traversal, such as round-robin scheduling or buffering systems. Understanding their operations and behavior equips you to handle efficient data structures for cyclic problems.
Stay tuned for more demystified data structures and algorithms!
Top comments (0)