Before starting this tutorial, make sure to check out Linked Lists: One Step at a Time! to understand the basics of singly linked lists first.
First Step: What is a Circular Linked List?
Explanation:
A circular linked list is similar to a singly linked list, but with one key difference.
The last node's next pointer points back to the first node instead of NULL.
This creates a circular structure with no beginning or end.
We often keep a pointer to the last node (tail) for efficient operations.
The node structure is the same as a singly linked list.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
Second Step: Creating Two Nodes and Making Them Circular
Explanation:
Create two nodes.
Set the first node to point to the second node.
Set the second node to point back to the first node (making it circular).
Keep a pointer to the last node for easy access.
Assign values to the nodes using scanf.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
int main() {
struct Node* first = (struct Node*)malloc(sizeof(struct Node));
struct Node* second = (struct Node*)malloc(sizeof(struct Node));
printf("Enter value for the first node: ");
scanf("%d", &first->data);
first->next = second;
printf("Enter value for the second node: ");
scanf("%d", &second->data);
second->next = first;
struct Node* last = second;
free(first);
free(second);
return 0;
}
Third Step: Creating Three Nodes in a Circular List
Explanation:
Create three nodes.
Link them in a chain where each node points to the next node.
The last node points back to the first node, completing the circle.
This creates a circular structure: 1 -> 2 -> 3 -> 1 -> ...
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
int main() {
struct Node* first = (struct Node*)malloc(sizeof(struct Node));
struct Node* second = (struct Node*)malloc(sizeof(struct Node));
struct Node* third = (struct Node*)malloc(sizeof(struct Node));
printf("Enter value for the first node: ");
scanf("%d", &first->data);
first->next = second;
printf("Enter value for the second node: ");
scanf("%d", &second->data);
second->next = third;
printf("Enter value for the third node: ");
scanf("%d", &third->data);
third->next = first;
struct Node* last = third;
free(first);
free(second);
free(third);
return 0;
}
Fourth Step: Creating a Circular Linked List of 10 Nodes in a Loop
Explanation:
Create a circular linked list with 10 nodes using a loop.
Instead of a head pointer, we'll use a last pointer (tail).
Each new node is inserted after the last node.
The final step links the last node back to the first node.
Use scanf to get values for each node from the user.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
int main() {
struct Node* last = NULL;
struct Node* newNode = NULL;
struct Node* first = NULL;
for (int i = 0; i < 10; i++) {
newNode = (struct Node*)malloc(sizeof(struct Node));
printf("Enter value for node %d: ", i + 1);
scanf("%d", &newNode->data);
if (last == NULL) {
last = newNode;
first = newNode;
newNode->next = newNode;
} else {
newNode->next = last->next;
last->next = newNode;
last = newNode;
}
}
if (last != NULL) {
last->next = first;
}
return 0;
}
Fifth Step: Printing the Circular Linked List
Explanation:
Write a function that takes the last pointer as a parameter.
Start from the first node (last->next).
Use a do-while loop to traverse the list until we come back to the start.
Be careful not to create an infinite loop!
Print the data of each node.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
int main() {
struct Node* last = NULL;
struct Node* newNode = NULL;
struct Node* first = NULL;
for (int i = 0; i < 5; i++) {
newNode = (struct Node*)malloc(sizeof(struct Node));
printf("Enter value for node %d: ", i + 1);
scanf("%d", &newNode->data);
if (last == NULL) {
last = newNode;
first = newNode;
newNode->next = newNode;
} else {
newNode->next = last->next;
last->next = newNode;
last = newNode;
}
}
printCircularList(last);
if (last != NULL) {
struct Node* temp = last->next;
while (temp != last) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
free(last);
}
return 0;
}
Sixth Step: Adding a Node at the Beginning
Explanation:
Write a function that takes a double pointer to the last pointer.
Create a new node, assign its value from the function parameter.
If the list is empty, make the node point to itself.
Otherwise, insert the new node after last (which makes it the first node).
The last pointer remains unchanged.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
void addNodeAtBeginning(struct Node** pointerToLast, int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
if (*pointerToLast == NULL) {
*pointerToLast = newNode;
newNode->next = newNode;
} else {
newNode->next = (*pointerToLast)->next;
(*pointerToLast)->next = newNode;
}
}
int main() {
struct Node* last = NULL;
for (int i = 1; i <= 3; i++) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = i;
if (last == NULL) {
last = newNode;
newNode->next = newNode;
} else {
newNode->next = last->next;
last->next = newNode;
last = newNode;
}
}
printf("Original list:\n");
printCircularList(last);
int newValue;
printf("Enter value for the new node at the beginning: ");
scanf("%d", &newValue);
addNodeAtBeginning(&last, newValue);
printf("After adding at beginning:\n");
printCircularList(last);
if (last != NULL) {
struct Node* temp = last->next;
while (temp != last) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
free(last);
}
return 0;
}
Seventh Step: Adding a Node at the End
Explanation:
Write a function that adds a node at the end of the circular list.
Create a new node, assign its value from the function parameter.
Insert the new node after the current last node.
Update the last pointer to point to the new node.
This operation is very efficient in circular lists!
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
void addNodeAtEnd(struct Node** pointerToLast, int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
if (*pointerToLast == NULL) {
*pointerToLast = newNode;
newNode->next = newNode;
} else {
newNode->next = (*pointerToLast)->next;
(*pointerToLast)->next = newNode;
*pointerToLast = newNode;
}
}
int main() {
struct Node* last = NULL;
for (int i = 1; i <= 3; i++) {
addNodeAtEnd(&last, i);
}
printf("Original list:\n");
printCircularList(last);
int newValue;
printf("Enter value for the new node at the end: ");
scanf("%d", &newValue);
addNodeAtEnd(&last, newValue);
printf("After adding at end:\n");
printCircularList(last);
if (last != NULL) {
struct Node* temp = last->next;
while (temp != last) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
free(last);
}
return 0;
}
Eighth Step: Deleting the First Node
Explanation:
Write a function that takes a double pointer to the last pointer.
Handle the special case of a single node (pointing to itself).
Save the first node (last->next).
Update last->next to skip the first node.
Free the memory of the old first node.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
void deleteFirstNode(struct Node** pointerToLast) {
if (*pointerToLast == NULL) {
return;
}
struct Node* first = (*pointerToLast)->next;
if (*pointerToLast == first) {
free(first);
*pointerToLast = NULL;
} else {
(*pointerToLast)->next = first->next;
free(first);
}
}
int main() {
struct Node* last = NULL;
for (int i = 1; i <= 4; i++) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = i;
if (last == NULL) {
last = newNode;
newNode->next = newNode;
} else {
newNode->next = last->next;
last->next = newNode;
last = newNode;
}
}
printf("Original list:\n");
printCircularList(last);
deleteFirstNode(&last);
printf("After deleting first node:\n");
printCircularList(last);
if (last != NULL) {
struct Node* temp = last->next;
while (temp != last) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
free(last);
}
return 0;
}
Ninth Step: Deleting a Node with a Specific Value
Explanation:
Write a function that takes a double pointer to the last pointer and a value.
Traverse the list to find the node with the given value.
Keep track of the previous node.
Handle special cases: single node, deleting last node, deleting first node.
Update the links to bypass the node and free its memory.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
void deleteNodeWithValue(struct Node** pointerToLast, int value) {
if (*pointerToLast == NULL) {
return;
}
struct Node* curr = (*pointerToLast)->next;
struct Node* prev = *pointerToLast;
if (curr == *pointerToLast && curr->data == value) {
free(curr);
*pointerToLast = NULL;
return;
}
do {
if (curr->data == value) {
prev->next = curr->next;
if (curr == *pointerToLast) {
*pointerToLast = prev;
}
free(curr);
return;
}
prev = curr;
curr = curr->next;
} while (curr != (*pointerToLast)->next);
printf("Value %d not found in the list\n", value);
}
int main() {
struct Node* last = NULL;
for (int i = 1; i <= 5; i++) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = i * 10;
if (last == NULL) {
last = newNode;
newNode->next = newNode;
} else {
newNode->next = last->next;
last->next = newNode;
last = newNode;
}
}
printf("Original list:\n");
printCircularList(last);
int valueToDelete;
printf("Enter value to delete: ");
scanf("%d", &valueToDelete);
deleteNodeWithValue(&last, valueToDelete);
printf("After deleting node with value %d:\n", valueToDelete);
printCircularList(last);
if (last != NULL) {
struct Node* temp = last->next;
while (temp != last) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
free(last);
}
return 0;
}
Tenth Step: Counting Nodes in a Circular List
Explanation:
Write a function that counts the total number of nodes in the circular list.
Start from the first node and traverse until we come back to the start.
Use a counter to keep track of the number of nodes.
Handle the empty list case.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
int countNodes(struct Node* last) {
if (last == NULL) {
return 0;
}
int count = 0;
struct Node* temp = last->next;
do {
count++;
temp = temp->next;
} while (temp != last->next);
return count;
}
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
int main() {
struct Node* last = NULL;
int n;
printf("How many nodes do you want to create? ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
printf("Enter value for node %d: ", i + 1);
scanf("%d", &newNode->data);
if (last == NULL) {
last = newNode;
newNode->next = newNode;
} else {
newNode->next = last->next;
last->next = newNode;
last = newNode;
}
}
printCircularList(last);
int nodeCount = countNodes(last);
printf("Total number of nodes: %d\n", nodeCount);
if (last != NULL) {
struct Node* temp = last->next;
while (temp != last) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
free(last);
}
return 0;
}
Bonus Step: Converting Between Singly and Circular Linked Lists
Explanation:
Write functions to convert a singly linked list to circular and vice versa.
To convert singly to circular: find the last node and make it point to the first.
To convert circular to singly: find the last node and make it point to NULL.
These conversions show the relationship between the two structures.
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void printSinglyList(struct Node* head) {
printf("Singly List: ");
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("NULL\n");
}
void printCircularList(struct Node* last) {
if (last == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = last->next;
printf("Circular List: ");
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != last->next);
printf("(back to %d)\n", last->next->data);
}
struct Node* convertToCircular(struct Node* head) {
if (head == NULL) {
return NULL;
}
struct Node* last = head;
while (last->next != NULL) {
last = last->next;
}
last->next = head;
return last;
}
struct Node* convertToSingly(struct Node* last) {
if (last == NULL) {
return NULL;
}
struct Node* head = last->next;
last->next = NULL;
return head;
}
int main() {
struct Node* head = NULL;
struct Node* temp = NULL;
for (int i = 1; i <= 4; i++) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = i;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
} else {
temp->next = newNode;
}
temp = newNode;
}
printf("Original singly linked list:\n");
printSinglyList(head);
struct Node* last = convertToCircular(head);
printf("\nAfter converting to circular:\n");
printCircularList(last);
head = convertToSingly(last);
printf("\nAfter converting back to singly:\n");
printSinglyList(head);
temp = head;
while (temp != NULL) {
struct Node* next = temp->next;
free(temp);
temp = next;
}
return 0;
}