6-5 - Circular Linked List
6-5 - Circular Linked List
A circular linked list is a data structure where the last node connects back to the first, forming a loop. This
structure allows for continuous traversal without any interruptions. Circular linked lists are especially helpful for
tasks like scheduling and managing playlists, this allowing for smooth navigation. In this tutorial, we’ll cover the
basics of circular linked lists, how to work with them, their advantages and disadvantages, and their applications.
In Circular Singly Linked List, each node has just one pointer called the “next” pointer. The next pointer of last
node points back to the first node and this results in forming a circle. In this type of Linked list we can only move
through the list in one direction.
In circular doubly linked list, each node has two pointers prev and next, similar to doubly linked list.
The prev pointer points to the previous node and the next points to the next node. Here, in addition to
the last node storing the address of the first node, the first node will also store the address of the last node.
Note: In this article, we will use the circular singly linked list to explain the working of circular linked lists.
Node(int value){
data = value;
next = nullptr;
}
};
In the code above, each node has data and a pointer to the next node. When we create multiple nodes for a
circular linked list, we only need to connect the last node back to the first one.
// Connect nodes
first->next = second;
second->next = last;
In the above code, we have created three nodes first, second, and last having values 2, 3, and 4 respectively.
Why have we taken a pointer that points to the last node instead of the first node?
For the insertion of a node at the beginning, we need to traverse the whole list. Also, for insertion at the end, the
whole list has to be traversed. If instead of the start pointer, we take a pointer to the last node, then in both cases
there won’t be any need to traverse the whole list. So insertion at the beginning or at the end takes constant time,
irrespective of the length of the list.
Operations on the Circular Linked list:
We can do some operations on the circular linked list similar to the singly and doubly linked list which are:
Insertion
Insertion at the empty list
Insertion at the beginning
Insertion at the end
Insertion at the given position
Deletion
Delete the first node
Delete the last node
Delete the node from any position
Searching
Note: We will be using the circular singly linked list to represent the working of the circular linked list.
To insert a node in empty circular linked list, creates a new node with the given data, sets its next pointer to
point to itself, and updates the last pointer to reference this new node.
1
#include <iostream>
2
using namespace std;
4
struct Node{
5
int data;
6
Node *next;
7
Node(int value){
8
data = value;
9
next = nullptr;
10
}
11
};
12
13
// Function to insert a node into an empty circular singly linked list
14
Node *insertInEmptyList(Node *last, int data){
15
if (last != nullptr) return last;
16
17
// Create a new node
18
Node *newNode = new Node(data);
19
20
// Point newNode to itself
Output
To insert a new node at the beginning of a circular linked list, we first create the new node and allocate
memory for it. If the list is empty (indicated by the last pointer being NULL), we make the new node point
to itself. If the list already contains nodes then we set the new node’s next pointer to point to the current
head of the list (which is last->next), and then update the last node’s next pointer to point to the new node.
This maintains the circular structure of the list.
Insertion at the beginning in circular linked list
1
#include <iostream>
2
using namespace std;
4
struct Node {
5
int data;
6
Node* next;
8
Node(int value)
9
{
10
data = value;
11
next = nullptr;
12
}
13
};
14
15
// Function to insert a node at the beginning of the
16
// circular linked list
17
Node* insertAtBeginning(Node* last, int value){
18
// Allocate memory for the new node and set its data
19
Node* newNode = new Node(value);
20
21
// If the list is empty, make the new node point to
22
// itself and set it as last
23
if (last == nullptr) {
24
newNode->next = newNode;
25
return newNode;
26
}
27
Output
Original list: 2 3 4
List after inserting 5 at the beginning: 5 2 3 4
To insert a new node at the end of a circular linked list, we first create the new node and allocate memory
for it. If the list is empty (mean, last or tail pointer being NULL), we initialize the list with the new node
and making it point to itself to form a circular structure. If the list already contains nodes then we set the
new node’s next pointer to point to the current head (which is tail->next), then update the current tail’s
next pointer to point to the new node. Finally, we update the tail pointer to the new node. This will ensure
that the new node is now the last node in the list while maintaining the circular linkage.
1
#include <iostream>
2
using namespace std;
3
4
struct Node{
5
int data;
6
Node *next;
7
Node(int value)
8
{
9
data = value;
10
next = nullptr;
11
}
12
};
13
14
// Function to insert a node at the end of a circular linked list
15
Node *insertEnd(Node *tail, int value)
16
{
17
Node *newNode = new Node(value);
18
if (tail == nullptr){
19
// If the list is empty, initialize it with the new node
20
tail = newNode;
21
22
// Point to itself to form a circular structure
23
newNode->next = newNode;
24
}
25
else{
26
// Insert new node after the current tail
27
// and update the tail pointer.
28
// New node points to the head node
29
newNode >next = tail >next;
Output
Original list: 2 3 4
List after inserting 5 and 6: 2 3 4 5 6
To insert a new node at a specific position in a circular linked list, we first check if the list is empty. If it is
and the position is not 1 then we print an error message because the position doesn’t exist in the list. If the
position is 1 then we create the new node and make it point to itself. If the list is not empty, we create the
new node and traverse the list to find the correct insertion point. If the position is 1, we insert the new node
at the beginning by adjusting the pointers accordingly. For other positions, we traverse through the list
until we reach the desired position and inserting the new node by updating the pointers. If the new node is
inserted at the end, we also update the last pointer to reference the new node, maintaining the circular
structure of the list.
1
#include <iostream>
2
using namespace std;
4
struct Node{
5
int data;
6
Node *next;
7
Node(int value){
8
data = value;
9
next = nullptr;
10
}
11
};
12
13
// Function to insert a node at a specific position in a circular linked list
14
Node *insertAtPosition(Node *last, int data, int pos){
15
if (last == nullptr){
16
// If the list is empty
17
if (pos != 1){
18
cout << "Invalid position!" << endl;
19
return last;
20
}
21
// Create a new node and make it point to itself
22
Node *newNode = new Node(data);
23
last = newNode;
24
last->next = last;
25
return last;
26
}
27
28
// Create a new node with the given data
29
Node *newNode = new Node(data);
30
31
// curr will point to head initially
32
Node *curr = last->next;
33
34
if (pos == 1){
35
// Insert at the beginning
36
Output
Original list: 2 3 4
List after insertions: 2 5 3 4
To delete the first node of a circular linked list, we first check if the list is empty. If it is then we print a
message and return NULL. If the list contains only one node (the head is the same as the last) then we
delete that node and set the last pointer to NULL. If there are multiple nodes then we update the last->next
pointer to skip the head node and effectively removing it from the list. We then delete the head node to free
the allocated memory. Finally, we return the updated last pointer, which still points to the last node in the
list.
Delete the first node in circular linked list
1
#include <iostream>
2
using namespace std;
4
struct Node {
5
int data;
6
Node* next;
7
Node(int value) {
8
data = value;
9
next = nullptr;
10
}
11
};
12
13
// Function to delete the first node of the circular linked list
14
Node* deleteFirstNode(Node* last) {
15
if (last == nullptr) {
16
// If the list is empty
17
cout << "List is empty" << endl;
18
return nullptr;
19
}
20
21
Node* head = last->next;
22
23
if (head == last) {
24
// If there is only one node in the list
25
delete head;
26
last = nullptr;
Output
Original list: 2 3 4
List after deleting first node: 3 4
To delete a specific node from a circular linked list, we first check if the list is empty. If it is then we print a
message and return nullptr. If the list contains only one node and it matches the key then we delete that
node and set last to nullptr. If the node to be deleted is the first node then we update the next pointer of the
last node to skip the head node and delete the head. For other nodes, we traverse the list using two
pointers: curr (to find the node) and prev (to keep track of the previous node). If we find the node with the
matching key then we update the next pointer of prev to skip the curr node and delete it. If the node is found
and it is the last node, we update the last pointer accordingly. If the node is not found then do nothing and
tail or last as it is. Finally, we return the updated last pointer.
1
#include <iostream>
2
using namespace std;
3
4
struct Node {
5
int data;
6
Node* next;
7
Node(int value) {
8
data = value;
9
next = nullptr;
10
}
11
};
12
13
// Function to delete a specific node in the circular linked list
14
Node* deleteSpecificNode(Node* last, int key) {
15
if (last == nullptr) {
16
// If the list is empty
17
cout << "List is empty, nothing to delete." << endl;
18
return nullptr;
19
}
20
21
Node* curr = last->next;
22
Node* prev = last;
23
24
// If the node to be deleted is the only node in the list
25
if (curr == last && curr->data == key) {
26
delete curr;
27
last = nullptr;
28
return last;
29
}
30
31
// If the node to be deleted is the first node
32
if (curr->data == key) {
33
last->next = curr->next;
34
delete curr;
35
return last;
36
}
37
Output
Original list: 2 3 4
List after deleting node 3: 2 4
To delete the last node in a circular linked list, we first check if the list is empty. If it is, we print a message
and return nullptr. If the list contains only one node (where the head is the same as the last), we delete that
node and set last to nullptr. For lists with multiple nodes, we need to traverse the list to find the second last
node. We do this by starting from the head and moving through the list until we reach the node whose next
pointer points to last. Once we find the second last node then we update its next pointer to point back to the
head, this effectively removing the last node from the list. We then delete the last node to free up memory
and return the updated last pointer, which now points to the last node.
Deletion at the end of Circular linked list
1
#include <iostream>
2
using namespace std;
4
struct Node {
5
int data;
6
Node* next;
7
Node(int value) {
8
data = value;
9
next = nullptr;
10
}
11
};
12
13
// Function to delete the last node in the circular linked list
14
Node* deleteLastNode(Node* last) {
15
if (last == nullptr) {
16
// If the list is empty
17
cout << "List is empty, nothing to delete." << endl;
18
return nullptr;
19
}
20
Node* head = last->next;
21
22
// If there is only one node in the list
23
if (head == last) {
24
delete last;
25
last = nullptr;
26
return last;
27
}
28
// Traverse the list to find the second last node
Output
Original list: 2 3 4
List after deleting last node: 2 3
To search for a specific value in a circular linked list, we first check if the list is empty. If it is then we return
false. If the list contains nodes then we start from the head node (which is the last->next) and traverse the
list. We use a pointer curr to iterate through the nodes until we reach back to the head. During traversal, if
we find a node whose data matches the given key then we return true to indicating that the value was found.
After the loop, we also check the last node to ensure we don’t miss it. If the key is not found after traversing
the entire list then we return false.
2
using namespace std;
4
struct Node {
5
int data;
6
Node* next;
7
Node(int value) {
8
data = value;
9
next = nullptr;
10
}
11
};
12
13
// Function to search for a specific value in the
14
// circular linked list
15
bool search(Node* last, int key) {
16
if (last == nullptr) {
17
// If the list is empty
18
return false;
19
}
20
21
Node* head = last->next;
22
Node* curr = head;
23
24
// Traverse the list to find the key
25
while (curr != last) {
26
if (curr->data == key) {
27
// Key found
28
return true;
29
}
30
Output
Original list: 2 3 4
Value 3 found in the list.