Circular Singly Linked List
A circular singly linked list is a variation of a singly linked list where the last node points back to the first node, forming a circular structure. It is a linear data structure consisting of a sequence of elements, called nodes, where each node points to the next node in the sequence. Unlike arrays, elements in a linked list are not stored in contiguous memory locations. Each node contains two fields:
- Data: The value or information stored in the node.
- Next Pointer: A reference (or pointer) to the next node in the sequence. In the case of the last node, the next pointer points back to the first node.
The circular singly linked list forms a linear collection of elements where each node points to its successor, and the last node points back to the first node, creating a circular structure. It is a dynamic data structure, meaning it can grow or shrink in size during runtime, as nodes can be added or removed without requiring memory to be reallocated.
The head is the first node in the list, and it serves as the entry point for traversing the list. In a circular singly linked list, the last node points back to the head, forming a loop. If the list is empty, the head points to NULL
.
Unlike arrays that have a fixed size, a circular singly linked list dynamically allocates memory for each node when it is created. This means the size of the list can grow or shrink as nodes are added or removed at runtime.
Insertions and deletions of nodes, particularly at the beginning or middle of the list, are more efficient compared to arrays since you do not need to shift elements.
Circular singly linked lists can be traversed in a loop starting from the head and continuing back to the head after reaching the tail. However, there is no way to traverse backward, which can be a limitation in some use cases.
The nodes in a circular singly linked list do not need to be stored in contiguous memory locations, unlike arrays. Each node is linked to the next through pointers, and they can be located anywhere in memory.
The size of the linked list is not fixed, and it is determined by the number of nodes present in the list at any given time. This makes it more flexible for applications where the number of elements is unknown or changes frequently.
Each node in a circular singly linked list requires extra memory for the pointer (next reference), which slightly increases memory usage compared to arrays.
The last node in a circular singly linked list points back to the head, instead of having its next pointer set to NULL
.
Here's a visual representation of a circular singly linked list:
Head -> [Data | Next] -> [Data | Next] -> [Data | Next] -> Head
In the above representation:
- The
Head
points to the first node of the list. - Each node contains
Data
and aNext
pointer to the next node. - The last node's
Next
pointer points back to theHead
, indicating the circular structure.
A simple circular singly linked list with three nodes could look like this:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] -> Head
In the above example:
- The
Head
points to the first node containing the data10
. - The second node contains the data
20
and points to the third node. - The third node contains the data
30
and points back to theHead
, indicating the circular structure of the list.
Here's a detailed breakdown of common circular singly linked list operations:
insertAtBeginning()
:
- Description: Inserts a new node at the start (or head) of a circular singly linked list.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] -> Head
- You want to insert the value
5
at the beginning of the list. After callinginsertAtBeginning()
, the list becomes:
Head -> [5 | Next] -> [10 | Next] -> [20 | Next] -> [30 | Next] -> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity of inserting a node at the beginning of a circular singly linked list is \(O(1)\) (constant time). The following steps are performed:
- Create a new node.
- If the list is not empty, set the
next
pointer of the new node to point to the current head node (the first node in the list). If the list is empty, set thenext
pointer of the new node to point to itself, creating a circular structure. - Update the head pointer to point to the new node.
- If the list is not empty, the last node's
next
pointer should be updated to point to the new head.
Since no traversal is required, this operation takes constant time, \(O(1)\). - Space complexity: The space complexity of inserting a node at the beginning of a circular singly linked list is \(O(1)\) (constant space). The space required to allocate the new node is a fixed amount and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
insertAtEnd()
:
- Description: Inserts a new node at the end (or tail) of a circular singly linked list.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] -> Head
- You want to insert the value
40
at the end of the list. After callinginsertAtEnd()
, the list becomes:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] -> [40 | Next] -> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity of inserting a node at the end of a circular singly linked list is \(O(n)\) (linear time) in the general case.
- Best Case (Empty List): If the list is empty, inserting a new node at the end is the same as inserting at the beginning. The following steps are performed:
- Create a new node.
- Set the
next
pointer of the new node to point to itself, as it will be the only node in the list. - Update the head pointer to point to the new node.
Since no traversal is required, this operation takes constant time, \(O(1)\). - Average/Worst Case (Non-Empty List): If the list is not empty, you have to traverse the entire list to reach the last node. The following steps are performed:
- Start from the head node.
- Traverse the list by following the
next
pointers until you reach the last node (the node whosenext
pointer points to the head). - Create a new node.
- Set the
next
pointer of the new node to point to the head. - Update the
next
pointer of the last node to point to the new node.
The traversal takes \(O(n)\) time, where \(n\) is the number of nodes in the list. Updating the pointer takes \(O(1)\).
- Best Case (Empty List): If the list is empty, inserting a new node at the end is the same as inserting at the beginning. The following steps are performed:
- Space complexity: The space complexity of inserting a node at the end of a circular singly linked list is \(O(1)\) (constant space). The space required to allocate the new node is a fixed amount and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
insertAfterNode()
:
- Description: Inserts a new node in a singly linked list immediately after a given node. If the target node doesn't exist, you may opt to do nothing and just return control to the caller without modifying the list.
- Example:
- Suppose you have the following linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | NULL]
- You want to insert the value
25
after the node containing20
. After callinginsertAfterNode()
, the list becomes:
Head -> [10 | Next] -> [20 | Next] -> [25 | Next] -> [30 | NULL]
- Suppose you have the following linked list:
- Time complexity: The time complexity for inserting a node after a node in a singly linked list is \(O(1)\) (constant time). The following steps are performed:
- Create a new node.
- Set the
next
pointer of the new node to point to the node that follows the given node. - Update the
next
pointer of the given node to point to the new node.
Since no traversal is required, this operation takes constant time, \(O(1)\). - Space complexity: The space complexity for inserting a node after a node in a singly linked list is \(O(1)\) (constant time). The space required to allocate the new node is a fixed amount and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
insertAfterNode()
:
- Description: Inserts a new node in a circular singly linked list immediately after a given node. If the target node doesn't exist, the function does nothing and simply returns control to the caller without modifying the list.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] > Head
- You want to insert the value
25
after the node containing20
. After callinginsertAfterNode()
, the list becomes:
Head -> [10 | Next] -> [20 | Next] -> [25 | Next] -> [30 | Next] -> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity for inserting a node after a given node in a circular singly linked list is \(O(1)\) (constant time). The following steps are performed:
- Create a new node.
- Set the
next
pointer of the new node to point to the node that follows the given node. - Update the
next
pointer of the given node to point to the new node.
Since no traversal is required, this operation takes constant time, \(O(1)\). - Space complexity: The space complexity for inserting a node after a node in a circular singly linked list is \(O(1)\) (constant time). The space required to allocate the new node is a fixed amount and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
insertAtPosition()
:
- Description: Inserts a new node at a specified position in a circular singly linked list. Positions are usually indexed starting from 0 or 1. If the position is 1 (or 0, based on indexing), this implies insertion at the beginning of the list. If the position is greater than the size of the list or less than 1, the function may return an error or take no action since the insertion would be out of range.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] > Head
- You want to insert a new node with value
35
at position3
. After callinginsertAtPosition()
, the list becomes:
Head -> [10 | Next] -> [20 | Next] -> [35 | Next] -> [30 | Next] -> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity for inserting a new node at a specified position in a circular singly linked list is \(O(n)\) (linear time). The following steps are performed:
- Create a new node.
- Locate the preceding node (the node whose
next
pointer points to the target position). - Update the
next
pointer of the new node to point to the next node in the sequence. - Update the
next
pointer of the preceding node to point to the new node.
The traversal takes \(O(n)\) time, where \(n\) is the number of nodes in the list. Updating the pointers takes \(O(1)\). - Space complexity: The space complexity of inserting a new node at a specified position in a circular singly linked list is \(O(1)\) (constant space). The space required to allocate the new node is a fixed amount and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
deleteAtBeginning()
:
- Description: Removes a node at the start (or head) of a circular singly linked list. If the list is empty, it prints a message "List is empty" and returns, since there is no node to delete.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] > Head
- You want to delete the value
10
at the beginning of the list. After callingdeleteAtBeginning()
, the list becomes:
Head -> [20 | Next] -> [30 | Next]-> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity for removing a node at the beginning of a circular singly linked list is \(O(1)\) (constant time). The following steps are performed:
- If the list is empty, return.
- If there is only one node, set the head to
NULL
(empty list). - Otherwise:
- Find the last node in the list (the node pointing to head).
- Update the last node's
next
pointer to point to the second node. - Set the head pointer to the second node.
- Deallocate the memory of the old head node.
- Space complexity: The space complexity for removing a node at the beginning of a circular singly linked list is \(O(1)\) (constant space). Only a fixed amount of space is used to store references to the head node and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
deleteAtEnd()
:
- Description: Removes a node at the end (or tail) of a circular singly linked list. If the list is empty, it prints a message "List is empty" and returns, since there is no node to delete.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] > Head
- You want to remove the value
30
at the end of the list. After callingdeleteAtEnd()
, the list becomes:
Head -> [10 | Next] -> [20 | Next] -> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity for removing a node at the end of a circular singly linked list is \(O(n)\) (linear time). The following steps are performed:
- If the list is empty, return.
- If there is only one node, set the head to
NULL
(empty list). - Otherwise:
- Start from the head node.
- Traverse the list to find the second-to-last node (the node whose
next
pointer points to the last node). - Update the
next
pointer of the second-to-last node to point to the head, maintaining the circular structure. - Deallocate the memory for the old last node.
- Space complexity: The space complexity for removing a node at the end of a circular singly linked list is \(O(1)\) (constant space). Only a fixed amount of space is used to store references and does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
deleteAtPosition()
:
- Description: Removes a node at a specified position in a circular singly linked list. Positions are usually indexed starting from 0 or 1. If the position is 0 (or 1, based on indexing), it means the head node should be removed. If the specified position is out of bounds, a message is printed, and no changes are made to the list.
- Example:
- Suppose you have the following circular singly linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] > Head
- You want to remove the node at position
2
. After callingdeleteAtPosition()
, the list becomes:
Head -> [10 | Next] -> [30 | Next] -> Head
- Suppose you have the following circular singly linked list:
- Time complexity: The time complexity for removing a node at a specified position in a circular singly linked list is \(O(n)\) (linear time). The following steps are performed:
- If the list is empty, return.
- If the position is 0 (or 1, based on indexing), remove the head node:
- If there is only one node, set
head = NULL
. - Otherwise, find the last node (the node whose
next
points to the head). - Update the head pointer to the next node.
- Update the last node's
next
pointer to point to the new head. - Deallocate the memory of the removed node.
- If there is only one node, set
- If the position is greater than 0, traverse the list to find the node before the target node.
- Update its
next
pointer to skip the target node and point to the node after it. - Deallocate the memory of the removed node.
- Space complexity: The space complexity for removing a node at a specified position in a circular singly linked list is \(O(1)\) (constant space). Only a fixed amount of space is used to store references, and it does not depend on the size of the list. No additional data structures or auxiliary space are used in the process.
traverse()
:
- Description: Visits each node in a circular singly linked list and performs an action, such as printing the node's value. Unlike a singly linked list, traversal starts at the head and continues until the head is encountered again, ensuring the circular structure is maintained.
- Time complexity: The time complexity of the
traverse()
function in a circular singly linked list is \(O(n)\) (linear time). The function iterates through each node exactly once, from the head back to the head. Since every node is visited once, the number of operations performed is directly proportional to the number of nodes. - Space complexity: The space complexity of the
traverse()
function in a circular singly linked list is \(O(1)\) (constant space). The function only uses a constant amount of space to store variables such as the current node reference during the traversal. Regardless of the size of the linked list, the amount of extra space used does not change.
reverse()
:
- Description: Reverses the order of nodes in a circular singly linked list. Unlike a regular singly linked list, the last node's
next
pointer must be correctly updated to point to the new head, ensuring the circular structure is maintained. - Example:
- Suppose you have the following circular linked list:
Head -> [10 | Next] -> [20 | Next] -> [30 | Next] -> Head
- After calling
reverse()
, the list becomes:
Head -> [30 | Next] -> [20 | Next] -> [10 | Next] -> Head
- Suppose you have the following circular linked list:
- Time complexity: The time complexity of the
reverse()
function in a circular singly linked list is \(O(n)\) (linear time). The function traverses each node exactly once and updates pointers accordingly. - Space complexity: The space complexity of the
reverse()
function in a circular singly linked list is \(O(1)\) (constant space). The function only uses a fixed amount of extra space for variables, such as pointers for the current, previous, and next nodes, regardless of the list size.
- Description: Reverses the order of nodes in a circular singly linked list. Unlike a regular singly linked list, the last node's
search()
:
- Description: Finds whether a specific element (or key) exists in a circular singly linked list. Unlike a regular singly linked list, the traversal must stop when the search wraps around back to the head, ensuring we do not loop indefinitely.
- Time complexity: The time complexity of the
search()
function in a circular singly linked list is \(O(n)\) (linear time). The function may need to examine every node in the list before finding the key (or determining that it is not present). - Space complexity: The space complexity of the
search()
function in a circular singly linked list is \(O(1)\) (constant space). The function only uses a fixed amount of extra space to store variables, such as a pointer to the current node. No additional data structures are used.
size()
:
- Description: Calculates and returns the number of nodes in a circular singly linked list. Unlike a regular singly linked list, traversal must stop when the function loops back to the head to avoid infinite loops.
- Time complexity: The time complexity of the
size()
function in a circular singly linked list is \(O(n)\) (linear time). The function traverses the entire linked list once to count the number of nodes, where \(n\) is the number of nodes in the list. - Space complexity: The space complexity of the
size()
function in a circular singly linked list is \(O(1)\) (constant space). The function uses only a fixed amount of extra space for variables, regardless of the size of the list.
get()
:
- Description: Retrieves the value of a node in a circular singly linked list at a specified index. Since the list is circular, traversal stops when the head is encountered again. If the index is out of range, a message is printed indicating that the index is invalid.
- Time complexity: The time complexity of the
get()
function in a circular singly linked list is \(O(n)\) (linear time). The function traverses the list until it reaches the specified index, stopping if it loops back to the head before finding the index. - Space complexity: The space complexity of the
get()
function in a circular singly linked list is \(O(1)\) (constant space). The function only uses a fixed amount of extra space for variables, regardless of the list size.
set()
:
- Description: Updates the value of a node at a specified index in a circular singly linked list. Since the list is circular, traversal stops when the head is encountered again. If the index is out of range, a message is printed indicating that the index is invalid.
- Time complexity: The time complexity of the
set()
function in a circular singly linked list is \(O(n)\) (linear time). The function traverses the list until it reaches the specified index, stopping if it loops back to the head before finding the index. - Space complexity: The space complexity of the
set()
function in a circular singly linked list is \(O(1)\) (constant space). The function only uses a fixed amount of extra space for variables, regardless of the list size.
isEmpty()
:
- Description: Checks whether a circular singly linked list is empty.
- Time complexity: The time complexity of the
isEmpty()
function in a circular singly linked list is \(O(1)\) (constant time). The function only checks if the head pointer isNULL
, which takes constant time. - Space complexity: The space complexity of the
isEmpty()
function in a circular singly linked list is \(O(1)\) (constant space). The function does not use any additional memory beyond a single pointer check.
merge()
:
- Description: Combines two sorted circular singly linked lists into a single sorted circular singly linked list while maintaining circularity.
- Time complexity: The time complexity of the
merge()
function in a circular singly linked list is \(O(n + m)\) (linear time). Each node from both lists is visited exactly once, and linking operations are performed in constant time. Where \(n\) is the number of nodes in the first circular linked list and \(m\) is the number of nodes in the second circular linked list. - Space complexity: The space complexity of the
merge()
function in a circular singly linked list is \(O(1)\) (constant space). The function uses a fixed number of pointers without any additional data structures, ensuring that the space required does not depend on the size of the input lists.
sort()
:
- Description: Arranges the elements of a circular singly linked list in a specific order (typically ascending or descending) while maintaining its circular nature.
- Time complexity: The time complexity of the
sort()
function in a circular singly linked list, when using merge sort, is \(O(n \log n)\) (linearithmic time). The algorithm recursively divides the list into halves and requires \(O(n)\) time to merge them back together. The logarithmic factor \(\log n\) results from the number of times the list is split in half. - Space complexity: The space complexity of the
sort()
function in a circular singly linked list, using Merge Sort, is \(O(\log n)\) (logarithmic space) due to recursion depth. If implemented iteratively, space complexity can be reduced to \(O(1)\), ensuring no extra space is used beyond a few pointers.
clear()
:
- Description: Removes all nodes from a circular singly linked list, freeing up the memory they occupy and making the list empty. The head pointer is set to
NULL
, breaking the circular link. - Time complexity: The time complexity of the
clear()
function in a circular singly linked list is \(O(n)\) (linear time). The function traverses the list once, freeing each node's memory. - Space complexity: The space complexity of the
clear()
function in a circular singly linked list is \(O(1)\) (constant space). The function only uses a fixed amount of space for temporary pointers during traversal, regardless of the list size.
- Description: Removes all nodes from a circular singly linked list, freeing up the memory they occupy and making the list empty. The head pointer is set to
Non-Generic Circular Singly Linked List Implementation
Here is the Non-Generic circular singly linked list implementation in C:
#include <stdio.h>
#include <stdlib.h>
// Defines a structure to represent a node in a circular singly linked list
typedef struct Node {
int data;
struct Node* next;
} Node;
// Function to create a new node
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = newNode; // Points to itself initially (circular behavior)
return newNode;
}
// Function to insert a node at the beginning of the list
void insertAtBeginning(Node** headRef, int data) {
Node* newNode = createNode(data);
if (*headRef == NULL) {
*headRef = newNode;
} else {
Node* temp = *headRef;
while (temp->next != *headRef) { // Traverse until we find the last node
temp = temp->next;
}
temp->next = newNode; // Update last node's next to new node
newNode->next = *headRef; // New node points to head
*headRef = newNode; // Update head
}
}
// Function to insert a node at the end of the list
void insertAtEnd(Node** headRef, int data) {
if (*headRef == NULL) {
*headRef = createNode(data);
} else {
Node* temp = *headRef;
while (temp->next != *headRef) { // Traverse until we find the last node
temp = temp->next;
}
Node* newNode = createNode(data);
temp->next = newNode;
newNode->next = *headRef; // Make the new node point to the head
}
}
// Function to insert a new node after a given previous node
void insertAfterNode(Node* prevNode, int data) {
if (prevNode == NULL) {
printf("The given previous node cannot be NULL.\n");
return;
}
Node* newNode = createNode(data);
newNode->next = prevNode->next;
prevNode->next = newNode;
}
// Function to insert a node before a given next node
void insertBeforeNode(Node** headRef, Node* nextNode, int data) {
if (*headRef == NULL) {
printf("The list cannot be empty\n");
return;
}
if (nextNode == NULL) {
printf("The given next node cannot be NULL\n");
return;
}
Node* newNode = createNode(data);
if (*headRef == nextNode) { // If the nextNode is the head, insert at beginning
insertAtBeginning(headRef, data);
return;
}
Node* temp = *headRef;
while (temp != NULL && temp->next != nextNode) {
temp = temp->next;
}
if (temp == NULL) {
printf("The given next node is not found in the list\n");
free(newNode);
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
// Function to insert a node at a specific position (0-based index)
void insertAtPosition(Node** headRef, int data, int position) {
Node* newNode = createNode(data);
if (position == 0) { // Insert at the beginning
insertAtBeginning(headRef, data);
return;
}
Node* temp = *headRef;
for (int i = 0; i < position - 1 && temp != NULL; i++) {
temp = temp->next;
}
if (temp == NULL) {
printf("Position out of bounds\n");
free(newNode);
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
// Function to delete a node at the beginning of the list
void deleteAtBeginning(Node** headRef) {
if (*headRef == NULL) {
printf("List is empty\n");
return;
}
Node* temp = *headRef;
if (temp->next == *headRef) { // If there's only one node
free(temp);
*headRef = NULL;
return;
}
// Traverse to the last node
Node* last = *headRef;
while (last->next != *headRef) {
last = last->next;
}
last->next = (*headRef)->next; // Last node's next points to second node
*headRef = (*headRef)->next; // Update head
free(temp);
}
// Function to delete a node at the end of the list
void deleteAtEnd(Node** headRef) {
if (*headRef == NULL) {
printf("List is empty\n");
return;
}
Node* temp = *headRef;
if (temp->next == *headRef) { // Only one node
free(temp);
*headRef = NULL;
return;
}
// Traverse to the second last node
Node* last = *headRef;
while (last->next != *headRef) {
last = last->next;
}
// Delete last node
Node* secondLast = *headRef;
while (secondLast->next != last) {
secondLast = secondLast->next;
}
secondLast->next = *headRef; // Second last node points to head
free(last);
}
// Function to delete a node at a specific position (0-based index) in a circular singly linked list
void deleteAtPosition(Node** headRef, int position) {
if (*headRef == NULL) {
printf("List is empty\n");
return;
}
Node* temp = *headRef;
// If the position is 0, we need to delete the head
if (position == 0) {
// If there is only one node in the list
if (temp->next == *headRef) {
free(temp);
*headRef = NULL;
return;
}
// Traverse to the last node
Node* last = *headRef;
while (last->next != *headRef) {
last = last->next;
}
// Update the head and unlink the node
last->next = temp->next;
*headRef = temp->next;
free(temp);
return;
}
// Find the previous node of the node to be deleted
for (int i = 0; temp != NULL && i < position - 1; i++) {
temp = temp->next;
if (temp == *headRef) {
// If we have reached the head again, the position is out of bounds
printf("Position out of bounds\n");
return;
}
}
// If position is more than number of nodes or temp is NULL
if (temp == NULL || temp->next == *headRef) {
printf("Position out of bounds\n");
return;
}
// Node temp->next is the node to be deleted
Node* nodeToDelete = temp->next;
temp->next = nodeToDelete->next; // Unlink the node from the list
free(nodeToDelete); // Free the memory of the deleted node
}
// Function to traverse the circular list and print all elements
void traverse(Node* head) {
if (head == NULL) {
printf("List is empty.\n");
return;
}
Node* temp = head;
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != head); // Stop when we reach the head again
printf("(head)\n");
}
// Function to search for an element in the list
int search(Node* head, int key) {
if (head == NULL) return 0;
Node* temp = head;
do {
if (temp->data == key)
return 1;
temp = temp->next;
} while (temp != head);
return 0;
}
// Function to get the size of the circular linked list
int size(Node* head) {
if (head == NULL) return 0;
int size = 1;
Node* temp = head->next;
while (temp != head) {
size++;
temp = temp->next;
}
return size;
}
// Function to check if the list is empty
int isEmpty(Node* head) {
return head == NULL;
}
// Function to access an element at a specific index (0-based)
int get(Node* head, int index) {
if (head == NULL) return -1;
int count = 0;
Node* temp = head;
do {
if (count == index)
return temp->data;
count++;
temp = temp->next;
} while (temp != head);
return -1; // Index out of range
}
// Function to set an element at a specific index (0-based)
void set(Node* head, int index, int newValue) {
if (head == NULL) {
printf("List is empty\n");
return;
}
int count = 0;
Node* current = head;
do {
if (count == index) {
current->data = newValue; // Update the node's value
return;
}
count++;
current = current->next;
} while (current != head);
printf("Index out of range\n"); // Handle case where index exceeds list length
}
// Function to reverse the circular linked list
void reverse(Node** headRef) {
if (*headRef == NULL || (*headRef)->next == *headRef) {
return; // No need to reverse for empty or single node
}
Node *prev = NULL, *current = *headRef, *next = NULL;
do {
next = current->next;
current->next = prev;
prev = current;
current = next;
} while (current != *headRef);
(*headRef)->next = prev; // Make the last node point to the new head
*headRef = prev;
}
// Function to clear the entire circular linked list and free memory
void clear(Node** headRef) {
if (*headRef == NULL) return;
Node* current = *headRef;
Node* next;
do {
next = current->next;
free(current);
current = next;
} while (current != *headRef);
*headRef = NULL;
}
// Function to find the middle of a circular singly linked list
void middle(Node** mid, Node* head) {
if (head == NULL || head->next == head) {
*mid = head;
return;
}
Node* slow = head;
Node* fast = head;
// Move fast two steps and slow one step
while (fast->next != head && fast->next->next != head) {
fast = fast->next->next;
slow = slow->next;
}
*mid = slow;
}
// Function to merge two circular linked lists
void merge(Node** headRef, Node* head1, Node* head2) {
Node* tempHead = NULL, *last = NULL;
Node* first1 = head1, *first2 = head2;
printf("Starting merge...\n");
if (head1 == NULL) {
printf("First list is empty. Returning a new node from the second list.\n");
Node* newNode = createNode(head2->data); // Create a new node with the data of the first node of head2
*headRef = newNode; // Set the new node as the head
head2 = head2->next;
if (head2 == first2) head2 = NULL; // Handle circular structure
return;
}
if (head2 == NULL) {
printf("Second list is empty. Returning a new node from the first list.\n");
Node* newNode = createNode(head1->data); // Create a new node with the data of the first node of head1
*headRef = newNode; // Set the new node as the head
head1 = head1->next;
if (head1 == first1) head1 = NULL; // Handle circular structure
return;
}
printf("Both lists are non-empty. Merging...\n");
do {
Node* newNode;
if (head1 && (head2 == NULL || head1->data <= head2->data)) {
printf("Adding node from List 1: %d\n", head1->data);
newNode = createNode(head1->data);
head1 = head1->next;
if (head1 == first1) {
printf("End of List 1 reached.\n");
head1 = NULL; // Stop merging this list
}
} else {
printf("Adding node from List 2: %d\n", head2->data);
newNode = createNode(head2->data);
head2 = head2->next;
if (head2 == first2) {
printf("End of List 2 reached.\n");
head2 = NULL;
}
}
if (!tempHead) {
tempHead = newNode;
printf("New head node created: %d\n", tempHead->data);
} else {
last->next = newNode;
}
last = newNode;
} while (head1 != NULL || head2 != NULL);
// Make the list circular
last->next = tempHead;
*headRef = tempHead;
printf("Merge completed. Circular list created with head: %d\n", (*headRef)->data);
}
// Function to sort a circular singly linked list (Merge Sort)
void sort(Node** headRef) {
if (*headRef == NULL || (*headRef)->next == *headRef)
return;
Node* head = *headRef;
Node* mid = NULL;
middle(&mid, head);
Node* nextToMid = mid->next;
mid->next = head; // Break circularity for first half
Node* secondHalf = nextToMid;
// Find last node of second half
while (secondHalf->next != head)
secondHalf = secondHalf->next;
secondHalf->next = nextToMid; // Break circularity for second half
// Sort both halves
sort(&head);
sort(&nextToMid);
// Merge sorted halves
merge(headRef, head, nextToMid);
}
// Main function to test the circular linked list operations
int main() {
Node* list = NULL; // Initialize an empty linked list
// 1. Insert elements at the beginning
insertAtBeginning(&list, 5);
insertAtBeginning(&list, 3);
insertAtBeginning(&list, 1);
printf("List after inserting at the beginning: ");
traverse(list);
// 2. Insert elements at the end
insertAtEnd(&list, 7);
insertAtEnd(&list, 9);
printf("List after inserting at the end: ");
traverse(list);
// 3. Insert element at position 2
insertAtPosition(&list, 4, 2);
printf("List after inserting 4 at position 2: ");
traverse(list);
// 4. Insert element after the second node
Node* secondNode = list->next;
insertAfterNode(secondNode, 6);
printf("List after inserting 6 after the second node: ");
traverse(list);
// 5. Insert element before the node with value 7
Node* temp = list;
while (temp != NULL && temp->data != 7) {
temp = temp->next;
}
insertBeforeNode(&list, temp, 8);
printf("List after inserting 8 before the node with value 7: ");
traverse(list);
// 6. Delete the first node
deleteAtBeginning(&list);
printf("List after deleting the first node: ");
traverse(list);
// 7. Delete the last node
deleteAtEnd(&list);
printf("List after deleting the last node: ");
traverse(list);
// 8. Delete the node at position 2
deleteAtPosition(&list, 2);
printf("List after deleting the node at position 2: ");
traverse(list);
// 9. Check if list is empty
if (isEmpty(list)) {
printf("The list is empty.\n");
} else {
printf("The list is not empty.\n");
}
// 10. Search for an element
int key = 6;
if (search(list, key)) {
printf("Element %d found in the list.\n", key);
} else {
printf("Element %d not found in the list.\n", key);
}
// 11. Reverse the list
reverse(&list);
printf("List after reversing: ");
traverse(list);
// 12. Sort the list
sort(&list);
printf("List after sorting: ");
traverse(list);
// 13. Get the size of the list
printf("Size of the list: %d\n", size(list));
// 14. Access an element at a specific index
int index = 2;
int value = get(list, index);
if (value != -1) {
printf("Element at index %d: %d\n", index, value);
} else {
printf("Index %d is out of range.\n", index);
}
// 15. Set a new value at a specific index
set(list, 2, 10);
printf("List after setting value 10 at index 2: ");
traverse(list);
// 16. Clear the list
clear(&list);
printf("List after clearing: ");
traverse(list);
return 0;
}
Here is the Non-Generic circular singly linked list implementation in C++:
#include <iostream>
using namespace std;
// Node structure for circular singly linked list
struct Node {
int data;
Node* next;
// Constructor to create a new node
Node(int data) : data(data), next(nullptr) {}
};
// Insert at the beginning
void insertAtBeginning(Node*& head, int data) {
Node* newNode = new Node(data);
if (!head) {
newNode->next = newNode;
head = newNode;
return;
}
Node* temp = head;
while (temp->next != head) temp = temp->next;
temp->next = newNode;
newNode->next = head;
head = newNode;
}
// Insert at the end
void insertAtEnd(Node*& head, int data) {
Node* newNode = new Node(data);
if (!head) {
newNode->next = newNode;
head = newNode;
return;
}
Node* temp = head;
while (temp->next != head) temp = temp->next;
temp->next = newNode;
newNode->next = head;
}
// Delete at the beginning
void deleteAtBeginning(Node*& head) {
if (!head) {
cout << "List is empty\n";
return;
}
if (head->next == head) {
delete head;
head = nullptr;
return;
}
Node* temp = head;
while (temp->next != head) temp = temp->next;
Node* toDelete = head;
temp->next = head->next;
head = head->next;
delete toDelete;
}
// Function to insert a new node after a given previous node
void insertAfterNode(Node* prevNode, int data) {
if (prevNode == nullptr) {
cout << "The given previous node cannot be NULL." << endl;
return;
}
Node* newNode = new Node(data);
// Insert the new node after the previous node
newNode->next = prevNode->next;
prevNode->next = newNode;
}
// Function to insert a new node before a given next node
void insertBeforeNode(Node*& headRef, Node* nextNode, int data) {
if (headRef == nullptr) {
cout << "The list cannot be empty." << endl;
return;
}
if (nextNode == nullptr) {
cout << "The given next node cannot be NULL." << endl;
return;
}
Node* newNode = new Node(data);
// If inserting before the head, update head reference
if (headRef == nextNode) {
// Find the last node to update its next pointer
Node* temp = headRef;
while (temp->next != headRef) {
temp = temp->next;
}
temp->next = newNode; // Update last node's next pointer
newNode->next = headRef;
headRef = newNode; // New node becomes the head
return;
}
// Find the node just before nextNode
Node* temp = headRef;
while (temp->next != headRef && temp->next != nextNode) {
temp = temp->next;
}
if (temp->next != nextNode) {
cout << "The given next node is not found in the list." << endl;
delete newNode;
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
// Function to insert at a specific position
void insertAtPosition(Node*& head, int data, int position) {
Node* newNode = new Node(data);
// If inserting at position 0 (beginning)
if (position == 0) {
if (head == nullptr) {
newNode->next = newNode; // First node points to itself
head = newNode;
} else {
// Find the last node
Node* temp = head;
while (temp->next != head) {
temp = temp->next;
}
// Insert the new node at the beginning
newNode->next = head;
temp->next = newNode;
head = newNode;
}
return;
}
// Traverse to the (position-1)th node
Node* temp = head;
for (int i = 0; i < position - 1 && temp->next != head; i++) {
temp = temp->next;
}
if (temp->next == head && position > 0) {
cout << "Position out of bounds.\n";
delete newNode;
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
// Delete at the end
void deleteAtEnd(Node*& head) {
if (!head) {
cout << "List is empty\n";
return;
}
if (head->next == head) {
delete head;
head = nullptr;
return;
}
Node* temp = head;
while (temp->next->next != head) temp = temp->next;
delete temp->next;
temp->next = head;
}
// Traverse the list
void traverse(Node* head) {
if (!head) {
cout << "List is empty\n";
return;
}
Node* temp = head;
do {
cout << temp->data << " -> ";
temp = temp->next;
} while (temp != head);
cout << "(head)\n";
}
// Function to delete a node at a specific position
void deleteAtPosition(Node*& head, int position) {
if (head == nullptr) {
cout << "List is empty\n";
return;
}
Node* temp = head;
// Case 1: Deleting the head node
if (position == 0) {
if (head->next == head) {
delete head; // Only one node in the list
head = nullptr;
return;
}
// Find the last node to update its next pointer
Node* last = head;
while (last->next != head) {
last = last->next;
}
last->next = head->next;
head = head->next;
delete temp;
return;
}
// Case 2: Deleting a node at position > 0
Node* prev = nullptr;
for (int i = 0; i < position; i++) {
prev = temp;
temp = temp->next;
// If we circle back to the head, position is out of bounds
if (temp == head) {
cout << "Position out of bounds\n";
return;
}
}
prev->next = temp->next;
delete temp;
}
// Function to check if the list is empty
bool isEmpty(Node* head) {
return head == nullptr;
}
// Function to access an element at a specific index (0-based)
int get(Node* head, int index) {
if (head == nullptr) {
cout << "List is empty\n";
return -1;
}
Node* temp = head;
int count = 0;
do {
if (count == index)
return temp->data;
count++;
temp = temp->next;
} while (temp != head);
cout << "Index out of range\n";
return -1;
}
// Function to set an element at a specific index (0-based)
void set(Node* head, int index, int newValue) {
if (head == nullptr) {
cout << "List is empty\n";
return;
}
Node* temp = head;
int count = 0;
do {
if (count == index) {
temp->data = newValue;
return;
}
count++;
temp = temp->next;
} while (temp != head);
cout << "Index out of range\n";
}
// Function to search for an element in a circular linked list
bool search(Node* head, int key) {
if (head == nullptr) return false;
Node* temp = head;
do {
if (temp->data == key)
return true;
temp = temp->next;
} while (temp != head);
return false;
}
// Reverse the list
void reverse(Node*& head) {
if (!head || head->next == head) return;
Node* prev = nullptr, *current = head, *next = nullptr, *tail = head;
do {
next = current->next;
current->next = prev;
prev = current;
current = next;
} while (current != head);
head->next = prev;
head = prev;
}
// Get size of the list
int size(Node* head) {
if (!head) return 0;
int count = 0;
Node* temp = head;
do {
count++;
temp = temp->next;
} while (temp != head);
return count;
}
// Clear the list
void clear(Node*& head) {
if (!head) return; // If the list is empty, return immediately.
Node* temp = head;
Node* nextNode;
// Traverse and delete each node
while (temp->next != head) {
nextNode = temp->next;
delete temp;
temp = nextNode;
}
// Delete the last remaining node
delete temp;
head = nullptr; // Set head to null after clearing the list
}
// Function to merge two sorted circular linked lists
void merge(Node*& headRef, Node* head1, Node* head2) {
Node* tempHead = nullptr, *last = nullptr;
Node* first1 = head1, *first2 = head2;
//std::cout << "Starting merge...\n";
if (head1 == nullptr) {
//std::cout << "First list is empty. Returning a new node from the second list.\n";
Node* newNode = new Node(head2->data); // Create a new node with the data of the first node of head2
headRef = newNode; // Set the new node as the head
head2 = head2->next;
if (head2 == first2) head2 = nullptr; // Handle circular structure
return;
}
if (head2 == nullptr) {
//std::cout << "Second list is empty. Returning a new node from the first list.\n";
Node* newNode = new Node(head1->data); // Create a new node with the data of the first node of head1
headRef = newNode; // Set the new node as the head
head1 = head1->next;
if (head1 == first1) head1 = nullptr; // Handle circular structure
return;
}
//std::cout << "Both lists are non-empty. Merging...\n";
do {
Node* newNode;
if (head1 && (head2 == nullptr || head1->data <= head2->data)) {
//std::cout << "Adding node from List 1: " << head1->data << "\n";
newNode = new Node(head1->data);
head1 = head1->next;
if (head1 == first1) {
//std::cout << "End of List 1 reached.\n";
head1 = nullptr; // Stop merging this list
}
} else {
//std::cout << "Adding node from List 2: " << head2->data << "\n";
newNode = new Node(head2->data);
head2 = head2->next;
if (head2 == first2) {
//std::cout << "End of List 2 reached.\n";
head2 = nullptr;
}
}
if (!tempHead) {
tempHead = newNode;
//std::cout << "New head node created: " << tempHead->data << "\n";
} else {
last->next = newNode;
}
last = newNode;
} while (head1 != nullptr || head2 != nullptr);
// Make the list circular
last->next = tempHead;
headRef = tempHead;
//std::cout << "Merge completed. Circular list created with head: " << headRef->data << "\n";
}
// Function to find the middle of a circular linked list
void middle(Node*& mid, Node* head) {
if (head == nullptr || head->next == head) { // Check if list is empty or contains one node
mid = head;
return;
}
Node* slow = head;
Node* fast = head;
// Move fast two steps and slow one step
while (fast->next != head && fast->next->next != head) {
fast = fast->next->next;
slow = slow->next;
}
mid = slow; // Assign the slow pointer to mid (middle node)
}
void sort(Node*& headRef) {
// If the list is empty or contains a single node, no need to sort
if (headRef == nullptr || headRef->next == headRef)
return;
Node* head = headRef;
Node* mid = nullptr;
// Find the middle node
middle(mid, head);
Node* nextToMid = mid->next;
mid->next = head; // Break circularity for first half
Node* secondHalf = nextToMid;
// Find the last node of the second half
while (secondHalf->next != head)
secondHalf = secondHalf->next;
secondHalf->next = nextToMid; // Break circularity for second half
// Sort both halves recursively
sort(head);
sort(nextToMid);
// Merge the sorted halves
merge(headRef, head, nextToMid);
}
int main() {
Node* list = nullptr; // Initialize an empty linked list
// 1. Insert elements at the beginning
insertAtBeginning(list, 5);
insertAtBeginning(list, 3);
insertAtBeginning(list, 1);
std::cout << "List after inserting at the beginning: ";
traverse(list);
// 2. Insert elements at the end
insertAtEnd(list, 7);
insertAtEnd(list, 9);
std::cout << "List after inserting at the end: ";
traverse(list);
// 3. Insert element at position 2
insertAtPosition(list, 4, 2);
std::cout << "List after inserting 4 at position 2: ";
traverse(list);
// 4. Insert element after the second node
Node* secondNode = list->next;
insertAfterNode(secondNode, 6);
std::cout << "List after inserting 6 after the second node: ";
traverse(list);
// 5. Insert element before the node with value 7
Node* temp = list;
while (temp != nullptr && temp->data != 7) {
temp = temp->next;
}
insertBeforeNode(list, temp, 8);
std::cout << "List after inserting 8 before the node with value 7: ";
traverse(list);
// 6. Delete the first node
deleteAtBeginning(list);
std::cout << "List after deleting the first node: ";
traverse(list);
// 7. Delete the last node
deleteAtEnd(list);
std::cout << "List after deleting the last node: ";
traverse(list);
// 8. Delete the node at position 2
deleteAtPosition(list, 2);
std::cout << "List after deleting the node at position 2: ";
traverse(list);
// 9. Check if the list is empty
if (isEmpty(list)) {
cout << "The list is empty." << endl;
} else {
cout << "The list is not empty." << endl;
}
// 10. Search for an element
int key = 6;
if (search(list, key)) {
std::cout << "Element " << key << " found in the list." << std::endl;
} else {
std::cout << "Element " << key << " not found in the list." << std::endl;
}
// 11. Reverse the list
reverse(list);
std::cout << "List after reversing: ";
traverse(list);
// 12. Sort the list
sort(list);
std::cout << "List after sorting: ";
traverse(list);
// 13. Get the size of the list
std::cout << "Size of the list: " << size(list) << std::endl;
// 14. Access an element at a specific index
int index = 2;
int value = get(list, index);
if (value != -1) {
std::cout << "Element at index " << index << ": " << value << std::endl;
} else {
std::cout << "Index " << index << " is out of range." << std::endl;
}
// 15. Set a new value at a specific index
set(list, 2, 10);
std::cout << "List after setting value 10 at index 2: ";
traverse(list);
// 16. Clear the list
clear(list);
std::cout << "List after clearing: ";
traverse(list);
return 0;
}
Here is the Non-Generic circular singly linked list implementation in Java:
public class CircularLinkedList {
// Node structure for a circular singly linked list
static class Node {
int data;
Node next;
// Constructor
Node(int data) {
this.data = data;
this.next = null;
}
}
// Insert at the beginning
public static Node insertAtBeginning(Node head, int data) {
Node newNode = new Node(data);
if (head == null) {
newNode.next = newNode; // Make it circular
return newNode;
}
Node temp = head;
while (temp.next != head) {
temp = temp.next;
}
temp.next = newNode;
newNode.next = head;
return newNode; // New head
}
// Insert at the end
public static Node insertAtEnd(Node head, int data) {
Node newNode = new Node(data);
if (head == null) {
newNode.next = newNode;
return newNode;
}
Node temp = head;
while (temp.next != head) {
temp = temp.next;
}
temp.next = newNode;
newNode.next = head;
return head; // Head remains the same
}
// Function to insert a new node after a given previous node
public static void insertAfterNode(Node prevNode, int data) {
if (prevNode == null) {
System.out.println("The given previous node cannot be NULL.");
return;
}
Node newNode = new Node(data);
newNode.next = prevNode.next;
prevNode.next = newNode;
}
// Function to insert a new node before a given next node
public static Node insertBeforeNode(Node head, Node nextNode, int data) {
if (head == null) {
System.out.println("The list cannot be empty.");
return null;
}
if (nextNode == null) {
System.out.println("The given next node cannot be NULL.");
return head;
}
Node newNode = new Node(data);
// If inserting before the head, update head reference
if (head == nextNode) {
Node temp = head;
while (temp.next != head) {
temp = temp.next;
}
temp.next = newNode; // Update last node's next pointer
newNode.next = head;
return newNode; // New node becomes the head
}
// Find the node just before nextNode
Node temp = head;
while (temp.next != head && temp.next != nextNode) {
temp = temp.next;
}
if (temp.next != nextNode) {
System.out.println("The given next node is not found in the list.");
return head;
}
newNode.next = temp.next;
temp.next = newNode;
return head;
}
// Insert at a specific position
public static Node insertAtPosition(Node head, int data, int position) {
if (position == 0) {
return insertAtBeginning(head, data);
}
Node newNode = new Node(data);
Node temp = head;
for (int i = 0; i < position - 1 && temp.next != head; i++) {
temp = temp.next;
}
newNode.next = temp.next;
temp.next = newNode;
return head;
}
// Delete at the beginning
public static Node deleteAtBeginning(Node head) {
if (head == null) {
System.out.println("List is empty");
return null;
}
if (head.next == head) {
return null;
}
Node temp = head;
while (temp.next != head) {
temp = temp.next;
}
temp.next = head.next;
return head.next;
}
// Delete at the end
public static Node deleteAtEnd(Node head) {
if (head == null || head.next == head) {
return null;
}
Node temp = head;
while (temp.next.next != head) {
temp = temp.next;
}
temp.next = head;
return head;
}
// Delete at a specific position
public static Node deleteAtPosition(Node head, int position) {
if (head == null) {
return null;
}
if (position == 0) {
return deleteAtBeginning(head);
}
Node temp = head;
for (int i = 0; i < position - 1 && temp.next != head; i++) {
temp = temp.next;
}
if (temp.next == head) {
return head;
}
temp.next = temp.next.next;
return head;
}
// Traverse the list
public static void traverse(Node head) {
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)");
}
// Check if the list is empty
public static boolean isEmpty(Node head) {
return head == null;
}
// Function to merge two sorted circular linked lists
public static Node merge(Node head1, Node head2) {
if (head1 == null) return head2;
if (head2 == null) return head1;
Node dummy = new Node(0); // Temporary dummy node
Node tail = dummy;
Node first1 = head1, first2 = head2;
do {
Node newNode;
if (head1 != null && (head2 == null || head1.data <= head2.data)) {
newNode = new Node(head1.data);
head1 = head1.next;
if (head1 == first1) head1 = null;
} else {
newNode = new Node(head2.data);
head2 = head2.next;
if (head2 == first2) head2 = null;
}
tail.next = newNode;
tail = newNode;
} while (head1 != null || head2 != null);
// Make the merged list circular
tail.next = dummy.next;
return dummy.next;
}
// Function to find the middle node of a circular linked list
public static Node middle(Node head) {
if (head == null || head.next == head) return head;
Node slow = head, fast = head;
while (fast.next != head && fast.next.next != head) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
// Function to sort a circular linked list using merge sort
public static Node sort(Node head) {
if (head == null || head.next == head) return head;
Node mid = middle(head);
Node secondHalf = mid.next;
mid.next = head; // Break circularity for the first half
// Find last node of second half and break circularity
Node temp = secondHalf;
while (temp.next != head) temp = temp.next;
temp.next = secondHalf;
// Recursively sort both halves
Node firstSorted = sort(head);
Node secondSorted = sort(secondHalf);
// Merge both halves
return merge(firstSorted, secondSorted);
}
// Function to get an element at a specific index (0-based)
public static int get(Node head, int index) {
if (head == null) {
System.out.println("List is empty");
return -1;
}
Node temp = head;
int count = 0;
do {
if (count == index)
return temp.data;
count++;
temp = temp.next;
} while (temp != head);
System.out.println("Index out of range");
return -1;
}
// Function to set an element at a specific index (0-based)
public static void set(Node head, int index, int newValue) {
if (head == null) {
System.out.println("List is empty");
return;
}
Node temp = head;
int count = 0;
do {
if (count == index) {
temp.data = newValue;
return;
}
count++;
temp = temp.next;
} while (temp != head);
System.out.println("Index out of range");
}
// Function to search for an element in a circular linked list
public static boolean search(Node head, int key) {
if (head == null) return false;
Node temp = head;
do {
if (temp.data == key)
return true;
temp = temp.next;
} while (temp != head);
return false;
}
// Function to reverse a circular linked list
public static Node reverse(Node head) {
if (head == null || head.next == head) return head;
Node prev = null, current = head, next = null;
Node tail = head;
do {
next = current.next;
current.next = prev;
prev = current;
current = next;
} while (current != head);
head.next = prev; // Fix circular link
return prev; // New head
}
// Get the size of the list
public static int size(Node head) {
if (head == null) return 0;
int count = 0;
Node temp = head;
do {
count++;
temp = temp.next;
} while (temp != head);
return count;
}
// Clear the circular linked list
public static void clear(Node head) {
if (head == null) {
System.out.println("List is already empty.");
return null;
}
Node current = head;
do {
Node next = current.next; // Save the next node
current.next = null; // Break the link to the next node
current = next; // Move to the next node
} while (current != head); // Loop until we reach the head node again
return null; // Return null to indicate the list is empty
}
// Main method for testing
public static void main(String[] args) {
Node head = null;
// 1. Insert elements at the beginning
head = insertAtBeginning(head, 5);
head = insertAtBeginning(head, 10);
head = insertAtBeginning(head, 3);
System.out.println("List after inserting at the beginning: ");
traverse(head);
// 2. Insert element at the end
head = insertAtEnd(head, 7);
head = insertAtEnd(head, 2);
System.out.println("List after inserting at the end: ");
traverse(head);
// 3. Insert at a specific position
head = insertAtPosition(head, 4, 2);
System.out.println("List after inserting at position 2: ");
traverse(head);
// 4. Insert after a specific node
insertAfterNode(head.next, 8);
System.out.println("List after inserting 8 after second node: ");
traverse(head);
// 5. Insert before a specific node
head = insertBeforeNode(head, head.next, 12);
System.out.println("List after inserting 12 before second node: ");
traverse(head);
// 6. Delete at the beginning
head = deleteAtBeginning(head);
System.out.println("List after deleting at the beginning: ");
traverse(head);
// 7. Delete at the end
head = deleteAtEnd(head);
System.out.println("List after deleting at the end: ");
traverse(head);
// 8. Delete at a specific position
head = deleteAtPosition(head, 2);
System.out.println("List after deleting at position 2: ");
traverse(head);
// 9. Check if the list is empty
if (isEmpty(head)) {
System.out.println("The list is empty.");
} else {
System.out.println("The list is not empty.");
}
// 10. Search for an element
int key = 7;
if (search(head, key)) {
System.out.println("Element " + key + " found in the list");
} else {
System.out.println("Element " + key + " not found in the list");
}
// 11. Reverse the list
head = reverse(head);
System.out.println("List after reversing: ");
traverse(head);
// 12. Get the size of the list
System.out.println("Size of the list: " + size(head));
// 13. Get element at a specific index
int indexToGet = 2;
int value = get(head, indexToGet);
if (value != -1) {
System.out.println("Element at index " + indexToGet + ": " + value);
}
// 14. Set value at a specific index
int indexToSet = 1;
int newValue = 25;
System.out.println("Setting value at index " + indexToSet + " to " + newValue);
set(head, indexToSet, newValue);
System.out.println("Updated list after set operation:");
traverse(head);
// 15. Sort the list
head = sort(head);
System.out.println("Sorted list:");
traverse(head);
// 16. Clear the list
head = clear(head);
System.out.println("List after clearing: ");
traverse(head);
}
}
Here is the Non-Generic circular singly linked list implementation in C#:
using System;
public class CircularLinkedList
{
// Node structure for circular singly linked list
public class Node
{
public int Data;
public Node Next;
// Constructor to create a new node
public Node(int data)
{
Data = data;
Next = null;
}
}
// Insert at the beginning
public static Node InsertAtBeginning(Node head, int data)
{
Node newNode = new Node(data);
if (head == null)
{
newNode.Next = newNode; // Circular link to itself if list is empty
return newNode;
}
Node temp = head;
// Traverse to the last node to point it to the new node
while (temp.Next != head)
{
temp = temp.Next;
}
temp.Next = newNode;
newNode.Next = head; // Link the new node to head
return newNode;
}
// Insert at the end
public static Node InsertAtEnd(Node head, int data)
{
Node newNode = new Node(data);
if (head == null)
{
newNode.Next = newNode; // Circular link to itself if list is empty
return newNode;
}
Node temp = head;
// Traverse to the last node
while (temp.Next != head)
{
temp = temp.Next;
}
temp.Next = newNode;
newNode.Next = head; // Link the new node to head
return head;
}
// Insert at a specific position
public static Node InsertAtPosition(Node head, int data, int position)
{
Node newNode = new Node(data);
if (position == 0)
{
return InsertAtBeginning(head, data);
}
Node temp = head;
int count = 0;
// Traverse to the position where new node should be inserted
while (temp.Next != head && count < position - 1)
{
temp = temp.Next;
count++;
}
if (count != position - 1)
{
Console.WriteLine("Position out of bounds");
return head;
}
newNode.Next = temp.Next;
temp.Next = newNode;
return head;
}
// Insert after a given node
public static void InsertAfterNode(Node prevNode, int data)
{
if (prevNode == null)
{
Console.WriteLine("The given previous node cannot be null");
return;
}
Node newNode = new Node(data);
newNode.Next = prevNode.Next;
prevNode.Next = newNode;
}
// Insert before a given node
public static Node InsertBeforeNode(Node head, Node nextNode, int data)
{
if (nextNode == null)
{
Console.WriteLine("The given next node cannot be null");
return head;
}
if (head == nextNode)
{
return InsertAtBeginning(head, data);
}
Node temp = head;
while (temp.Next != head && temp.Next != nextNode)
{
temp = temp.Next;
}
if (temp.Next == nextNode)
{
Node newNode = new Node(data);
newNode.Next = nextNode;
temp.Next = newNode;
}
else
{
Console.WriteLine("The given next node is not present in the list");
}
return head;
}
// Delete at the beginning
public static Node DeleteAtBeginning(Node head)
{
if (head == null)
{
Console.WriteLine("List is empty");
return null;
}
if (head.Next == head) // Only one node in the list
{
return null;
}
Node temp = head;
// Traverse to the last node to point it to the second node
while (temp.Next != head)
{
temp = temp.Next;
}
temp.Next = head.Next;
return head.Next; // New head is the next node
}
// Delete at the end
public static Node DeleteAtEnd(Node head)
{
if (head == null)
{
Console.WriteLine("List is empty");
return null;
}
if (head.Next == head) // Only one node in the list
{
return null;
}
Node temp = head;
while (temp.Next.Next != head)
{
temp = temp.Next;
}
temp.Next = head; // Last node points to the head again
return head;
}
// Delete at a specific position
public static Node DeleteAtPosition(Node head, int position)
{
if (head == null)
{
Console.WriteLine("List is empty");
return null;
}
if (position == 0)
{
return DeleteAtBeginning(head);
}
Node temp = head;
int count = 0;
while (temp.Next != head && count < position - 1)
{
temp = temp.Next;
count++;
}
if (count != position - 1)
{
Console.WriteLine("Position out of bounds");
return head;
}
temp.Next = temp.Next.Next;
return head;
}
// Check if the list is empty
public static bool IsEmpty(Node head)
{
return head == null;
}
// Traverse the circular list
public static void Traverse(Node head)
{
if (head == null)
{
Console.WriteLine("List is empty.");
return;
}
Node temp = head;
do
{
Console.Write(temp.Data + " -> ");
temp = temp.Next;
} while (temp != head);
Console.WriteLine("(head)");
}
// Function to get an element at a specific index (0-based)
public static int Get(Node head, int index)
{
if (head == null)
{
Console.WriteLine("List is empty");
return -1;
}
Node temp = head;
int count = 0;
do
{
if (count == index)
return temp.Data; // Return the data at the specified index
count++;
temp = temp.Next;
} while (temp != head);
Console.WriteLine("Index out of range");
return -1; // If index is out of bounds
}
// Function to set an element at a specific index (0-based)
public static void Set(Node head, int index, int newValue)
{
if (head == null)
{
Console.WriteLine("List is empty");
return;
}
Node temp = head;
int count = 0;
do
{
if (count == index)
{
temp.Data = newValue; // Set the new value at the specified index
return;
}
count++;
temp = temp.Next;
} while (temp != head);
Console.WriteLine("Index out of range"); // If index is out of bounds
}
// Search for an element in the circular list
public static bool Search(Node head, int key)
{
if (head == null)
{
return false;
}
Node temp = head;
do
{
if (temp.Data == key)
{
return true;
}
temp = temp.Next;
} while (temp != head);
return false;
}
// Reverse the circular linked list
public static Node Reverse(Node head)
{
if (head == null || head.Next == head)
{
return head; // No reversal needed for empty or single-node list
}
Node prev = null;
Node current = head;
Node next = null;
do
{
next = current.Next;
current.Next = prev;
prev = current;
current = next;
} while (current != head);
head.Next = prev; // Circular link
return prev; // New head
}
// Get the size of the circular list
public static int Size(Node head)
{
if (head == null)
{
return 0;
}
int count = 0;
Node temp = head;
do
{
count++;
temp = temp.Next;
} while (temp != head);
return count;
}
// Function to merge two sorted circular linked lists
public static Node Merge(Node head1, Node head2)
{
if (head1 == null) return head2;
if (head2 == null) return head1;
Node dummy = new Node(0); // Temporary dummy node
Node tail = dummy;
Node first1 = head1, first2 = head2;
do
{
Node newNode;
if (head1 != null && (head2 == null || head1.Data <= head2.Data))
{
newNode = new Node(head1.Data);
head1 = head1.Next;
if (head1 == first1) head1 = null;
}
else
{
newNode = new Node(head2.Data);
head2 = head2.Next;
if (head2 == first2) head2 = null;
}
tail.Next = newNode;
tail = newNode;
} while (head1 != null || head2 != null);
// Make the merged list circular
tail.Next = dummy.Next;
return dummy.Next;
}
// Function to find the middle node of a circular linked list
public static Node Middle(Node head)
{
if (head == null || head.Next == head) return head;
Node slow = head, fast = head;
while (fast.Next != head && fast.Next.Next != head)
{
fast = fast.Next.Next;
slow = slow.Next;
}
return slow;
}
// Function to sort a circular linked list using merge sort
public static Node Sort(Node head)
{
if (head == null || head.Next == head) return head;
Node mid = Middle(head);
Node secondHalf = mid.Next;
mid.Next = head; // Break circularity for the first half
// Find last node of second half and break circularity
Node temp = secondHalf;
while (temp.Next != head) temp = temp.Next;
temp.Next = secondHalf;
// Recursively sort both halves
Node firstSorted = Sort(head);
Node secondSorted = Sort(secondHalf);
// Merge both halves
return Merge(firstSorted, secondSorted);
}
// Clear the circular linked list
public static Node Clear(Node head)
{
if (head == null)
{
Console.WriteLine("List is already empty.");
return null;
}
Node current = head;
do
{
Node next = current.Next; // Save the next node
current.Next = null; // Break the link to the next node
current = next; // Move to the next node
} while (current != head); // Loop until we reach the head node again
return null; // Return null to indicate the list is empty
}
// Main method to test
public static void Main(string[] args)
{
Node head = null;
// 1. Insert elements at the beginning
head = InsertAtBeginning(head, 5);
head = InsertAtBeginning(head, 10);
head = InsertAtBeginning(head, 3);
Console.WriteLine("List after inserting at the beginning:");
Traverse(head);
// 2. Insert element at the end
head = InsertAtEnd(head, 7);
head = InsertAtEnd(head, 2);
Console.WriteLine("List after inserting at the end:");
Traverse(head);
// 3. Insert at a specific position
head = InsertAtPosition(head, 4, 2);
Console.WriteLine("List after inserting at position 2:");
Traverse(head);
// 4. Insert after a specific node
InsertAfterNode(head.Next, 8);
Console.WriteLine("List after inserting 8 after second node:");
Traverse(head);
// 5. Insert before a specific node
head = InsertBeforeNode(head, head.Next, 12);
Console.WriteLine("List after inserting 12 before second node:");
Traverse(head);
// 6. Delete at the beginning
head = DeleteAtBeginning(head);
Console.WriteLine("List after deleting at the beginning:");
Traverse(head);
// 7. Delete at the end
head = DeleteAtEnd(head);
Console.WriteLine("List after deleting at the end:");
Traverse(head);
// 8. Delete at a specific position
head = DeleteAtPosition(head, 2);
Console.WriteLine("List after deleting at position 2:");
Traverse(head);
// 9. Check if the list is empty
if (IsEmpty(head))
{
Console.WriteLine("The list is empty.");
}
else
{
Console.WriteLine("The list is not empty.");
}
// 10. Search for an element
int key = 7;
if (Search(head, key))
{
Console.WriteLine($"Element {key} found in the list");
}
else
{
Console.WriteLine($"Element {key} not found in the list");
}
// 11. Reverse the list
head = Reverse(head);
Console.WriteLine("List after reversing:");
Traverse(head);
// 12. Get the size of the list
Console.WriteLine("Size of the list: " + Size(head));
// 13. Get value at a specific index
int indexToGet = 2; // 0-based index
int value = Get(head, indexToGet);
Console.WriteLine($"Value at index {indexToGet}: {value}");
// 14. Set a new value at a specific index
int indexToSet = 2; // 0-based index
int newValue = 99;
Set(head, indexToSet, newValue);
Console.WriteLine($"List after setting index {indexToSet} to {newValue}:");
Traverse(head);
// 15. Sort the list
head = Sort(head);
Console.WriteLine("Sorted list:");
Traverse(head);
// 16. Clear the list
head = Clear(head);
Console.WriteLine("List after clearing:");
Traverse(head);
}
}
Generic Circular Singly Linked List Implementation
Here is the Generic circular singly linked list implementation in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// StackElement structure to hold data and a toString function pointer
typedef struct {
void* data; // Pointer to hold the actual data
char* toString; // This will be modified to hold the string representation
} StackElement;
// Node structure for circular singly linked list
typedef struct Node {
StackElement element;
struct Node* next; // Pointer to the next node
} Node;
// Function to create a new node
Node* createNode(StackElement element) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->element = element;
newNode->next = newNode; // In circular list, the node points to itself initially
return newNode;
}
// Function to insert a node at the beginning of the list (in a circular way)
void insertAtBeginning(Node** head, StackElement element) {
Node* newNode = createNode(element);
if (*head == NULL) {
*head = newNode;
} else {
Node* temp = *head;
// Find the last node (which points to the head)
while (temp->next != *head) {
temp = temp->next;
}
temp->next = newNode; // Set the last node's next to new node
newNode->next = *head; // New node points to head
*head = newNode; // Update head to the new node
}
}
// Function to insert a node at the end of the list (in a circular way)
void insertAtEnd(Node** head, StackElement element) {
Node* newNode = createNode(element);
if (*head == NULL) {
*head = newNode;
} else {
Node* temp = *head;
// Find the last node
while (temp->next != *head) {
temp = temp->next;
}
temp->next = newNode; // Set the last node's next to new node
newNode->next = *head; // New node points to head
}
}
// Function to insert a node after a given previous node
void insertAfterNode(Node* prevNode, StackElement element) {
// Check if the previous node is NULL
if (prevNode == NULL) {
printf("The given previous node cannot be NULL\n");
return;
}
// Create the new node with the given StackElement
Node* newNode = createNode(element);
// Insert the new node after prevNode
newNode->next = prevNode->next;
prevNode->next = newNode;
}
// Function to insert a node before a given next node
void insertBeforeNode(Node** head, Node* nextNode, StackElement element) {
// Check if the head is NULL (list is empty)
if (*head == NULL) {
printf("The list cannot be empty\n");
return;
}
// Check if the nextNode is NULL
if (nextNode == NULL) {
printf("The given next node cannot be NULL\n");
return;
}
// Create the new node with the given StackElement
Node* newNode = createNode(element);
// If the nextNode is the head node, handle the insertion at beginning
if (*head == nextNode) {
// Insert the new node before the head node
Node* temp = *head;
while (temp->next != *head) { // Find the last node
temp = temp->next;
}
temp->next = newNode;
newNode->next = *head;
*head = newNode;
return;
}
Node* temp = *head;
while (temp != NULL && temp->next != nextNode) {
temp = temp->next;
}
// If temp is NULL, then nextNode is not found in the list
if (temp == NULL) {
printf("The given next node is not found in the list\n");
free(newNode);
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
// Function to insert a node at a specific position in a circular singly linked list
void insertAtPosition(Node** head, StackElement element, int position) {
// Create the new node with the given StackElement
Node* newNode = createNode(element);
// If the list is empty and position is 0, insert as the only node
if (*head == NULL) {
if (position == 0) {
*head = newNode;
newNode->next = *head; // Make it circular
} else {
printf("Position out of bounds\n");
}
return;
}
// If position is at the beginning (position 0)
if (position == 0) {
Node* temp = *head;
// Find the last node (that points to the head)
while (temp->next != *head) {
temp = temp->next;
}
// Insert the new node at the beginning
temp->next = newNode;
newNode->next = *head;
*head = newNode;
return;
}
// Traverse the list to find the correct position
Node* temp = *head;
for (int i = 0; i < position - 1 && temp->next != *head; i++) {
temp = temp->next;
}
// If position is greater than the number of nodes in the list
if (temp->next == *head && position > 0) {
printf("Position out of bounds\n");
free(newNode);
return;
}
// Insert the new node at the specified position
newNode->next = temp->next;
temp->next = newNode;
}
// Function to delete the first node
void deleteAtBeginning(Node** head) {
if (*head == NULL) {
printf("List is empty\n");
return;
}
if (*head == (*head)->next) {
free(*head);
*head = NULL;
} else {
Node* temp = *head;
// Find the last node
while (temp->next != *head) {
temp = temp->next;
}
temp->next = (*head)->next; // Last node points to the second node
free(*head);
*head = temp->next;
}
}
// Function to delete the last node
void deleteAtEnd(Node** head) {
if (*head == NULL) {
printf("List is empty\n");
return;
}
if (*head == (*head)->next) {
free(*head);
*head = NULL;
} else {
Node* temp = *head;
// Traverse to the second-last node
while (temp->next->next != *head) {
temp = temp->next;
}
free(temp->next); // Free the last node
temp->next = *head; // Set the second-last node's next to head
}
}
// Function to delete a node at a specific position
void deleteAtPosition(Node** head, int position) {
if (*head == NULL) {
printf("List is empty\n");
return;
}
if (position == 0) {
deleteAtBeginning(head);
return;
}
Node* temp = *head;
for (int i = 0; i < position - 1 && temp != NULL; i++) {
temp = temp->next;
}
if (temp == NULL || temp->next == *head) {
printf("Position out of bounds\n");
return;
}
Node* nodeToDelete = temp->next;
temp->next = nodeToDelete->next;
free(nodeToDelete);
}
// Function to traverse the list and print all elements
void traverse(Node* head) {
if (head == NULL) {
printf("List is empty\n");
return;
}
Node* temp = head;
do {
printf("%s -> ", temp->element.toString);
temp = temp->next;
} while (temp != head);
printf("HEAD\n"); // To signify it's a circular list
}
// Function to search for an element in the list
int search(Node* head, StackElement keyElement) {
if (head == NULL) {
return 0;
}
Node* temp = head;
do {
if (strcmp(temp->element.toString, keyElement.toString) == 0) {
return 1; // Found
}
temp = temp->next;
} while (temp != head);
return 0; // Not found
}
// Function to reverse the circular linked list (O(n) time complexity)
void reverse(Node** head) {
if (*head == NULL || (*head)->next == *head) {
return;
}
Node *prev = NULL, *current = *head, *next = NULL;
do {
next = current->next;
current->next = prev;
prev = current;
current = next;
} while (current != *head);
(*head)->next = prev;
*head = prev;
}
// Function to get the size of the list
int size(Node* head) {
int size = 0;
if (head == NULL) return size;
Node* temp = head;
do {
size++;
temp = temp->next;
} while (temp != head);
return size;
}
// Function to check if the list is empty
int isEmpty(Node* head) {
return head == NULL;
}
// Function to access an element at a specific index (0-based)
StackElement get(Node* head, int index) {
int count = 0;
Node* temp = head;
// If the list is empty
if (head == NULL) {
StackElement emptyElement = {NULL, ""};
return emptyElement; // Return empty element if the list is empty
}
// Traverse the list
do {
if (count == index) {
return temp->element; // Found the element at the specified index
}
count++;
temp = temp->next;
} while (temp != head); // Stop when we loop back to the head node
// If the index is out of range
StackElement emptyElement = {NULL, ""};
return emptyElement;
}
// Function to set an element at a specific index (0-based)
void set(Node* head, int index, StackElement element) {
Node* current = head;
int count = 0;
// If the list is empty
if (head == NULL) {
printf("List is empty\n");
return;
}
// Traverse the list
do {
if (count == index) {
current->element = element; // Update the node's value
return; // Exit after updating
}
count++;
current = current->next;
} while (current != head); // Stop when we loop back to the head node
printf("Index out of range\n"); // Handle case where index exceeds list length
}
// Function to find the middle of a circular singly linked list
void middle(Node** mid, Node* head) {
if (head == NULL || head->next == head) {
*mid = head;
return;
}
Node* slow = head;
Node* fast = head;
// Move fast two steps and slow one step
while (fast->next != head && fast->next->next != head) {
fast = fast->next->next;
slow = slow->next;
}
*mid = slow;
}
// Function to merge two circular linked lists
void merge(Node** headRef, Node* head1, Node* head2) {
Node* tempHead = NULL, *last = NULL;
Node* first1 = head1, *first2 = head2;
printf("Starting merge...\n");
if (head1 == NULL) {
printf("First list is empty. Returning a new node from the second list.\n");
Node* newNode = createNode(head2->element); // Create a new node with the data of the first node of head2
*headRef = newNode; // Set the new node as the head
head2 = head2->next;
if (head2 == first2) head2 = NULL; // Handle circular structure
return;
}
if (head2 == NULL) {
printf("Second list is empty. Returning a new node from the first list.\n");
Node* newNode = createNode(head1->element); // Create a new node with the data of the first node of head1
*headRef = newNode; // Set the new node as the head
head1 = head1->next;
if (head1 == first1) head1 = NULL; // Handle circular structure
return;
}
printf("Both lists are non-empty. Merging...\n");
do {
Node* newNode;
if (head1 && (head2 == NULL || strcmp(head1->element.toString, head2->element.toString) <= 0)) {
printf("Adding node from List 1: %s\n", head1->element.toString);
newNode = createNode(head1->element);
head1 = head1->next;
if (head1 == first1) {
printf("End of List 1 reached.\n");
head1 = NULL; // Stop merging this list
}
} else {
printf("Adding node from List 2: %s\n", head2->element.toString);
newNode = createNode(head2->element);
head2 = head2->next;
if (head2 == first2) {
printf("End of List 2 reached.\n");
head2 = NULL;
}
}
if (!tempHead) {
tempHead = newNode;
printf("New head node created: %s\n", tempHead->element.toString);
} else {
last->next = newNode;
}
last = newNode;
} while (head1 != NULL || head2 != NULL);
// Make the list circular
last->next = tempHead;
*headRef = tempHead;
printf("Merge completed. Circular list created with head: %s\n", (*headRef)->element.toString);
}
// Function to sort a circular singly linked list (Merge Sort)
void sort(Node** headRef) {
if (*headRef == NULL || (*headRef)->next == *headRef)
return;
Node* head = *headRef;
Node* mid = NULL;
middle(&mid, head);
Node* nextToMid = mid->next;
mid->next = head; // Break circularity for first half
Node* secondHalf = nextToMid;
// Find last node of second half
while (secondHalf->next != head)
secondHalf = secondHalf->next;
secondHalf->next = nextToMid; // Break circularity for second half
// Sort both halves
sort(&head);
sort(&nextToMid);
// Merge sorted halves
merge(headRef, head, nextToMid);
}
// Function to clear the entire linked list and free memory
void clear(Node** head) {
if (*head == NULL) return;
Node* current = *head;
Node* next = NULL;
do {
next = current->next;
free(current);
current = next;
} while (current != *head);
*head = NULL;
}
struct Person {
char name[20];
int age;
};
int main() {
// Create People
struct Person alice = {"Alice", 30};
struct Person john = {"John", 19};
struct Person albert = {"Albert", 28};
struct Person robert = {"Robert", 20};
// Create StackElement for people
StackElement personElement1 = {&alice, "Person{name:\"Alice\", age:30}"};
StackElement personElement2 = {&john, "Person{name:\"John\", age:19}"};
StackElement personElement3 = {&albert, "Person{name:\"Albert\", age:28}"};
StackElement personElement4 = {&robert, "Person{name:\"Robert\", age:20}"};
// Initialize Linked List
Node* personList = NULL;
// 1. **Insert elements at the beginning**
insertAtBeginning(&personList, personElement1);
insertAtBeginning(&personList, personElement2);
// 2. Insert elements at the end
insertAtEnd(&personList, personElement3);
insertAtEnd(&personList, personElement4);
printf("\nList after inserting elements:\n");
traverse(personList);
// 3. **Insert at a specific position**
StackElement newElement = {&alice, "Person{name:\"Eve\", age:22}"};
insertAtPosition(&personList, newElement, 2);
printf("\nList after inserting at position 2:\n");
traverse(personList);
// 4. **Insert before a node**
insertBeforeNode(&personList, personList->next, newElement);
printf("\nList after inserting before second node:\n");
traverse(personList);
// 5. **Insert after a node**
insertAfterNode(personList->next, newElement);
printf("\nList after inserting after second node:\n");
traverse(personList);
// 6. **Delete the first node**
deleteAtBeginning(&personList);
printf("\nList after deleting first node:\n");
traverse(personList);
// 7. **Delete the last node**
deleteAtEnd(&personList);
printf("\nList after deleting last node:\n");
traverse(personList);
// 8. **Delete at a specific position**
deleteAtPosition(&personList, 1);
printf("\nList after deleting node at position 1:\n");
traverse(personList);
// 9. **Search for an element**
int found = search(personList, personElement3);
printf("\nSearch result for 'Albert': %s\n", found ? "Found" : "Not Found");
// 10. **Get size of list**
printf("\nSize of the list: %d\n", size(personList));
// 11. **Check if list is empty**
printf("\nIs the list empty? %s\n", isEmpty(personList) ? "Yes" : "No");
// 12. **Access an element by index**
StackElement retrievedElement = get(personList, 1);
printf("\nElement at index 1: %s\n", retrievedElement.toString);
// 13. **Modify an element at an index**
StackElement modifiedElement = {&john, "Person{name:\"Updated John\", age:25}"};
set(personList, 1, modifiedElement);
printf("\nList after updating element at index 1:\n");
traverse(personList);
// 14. **Sort the linked list**
sort(&personList);
printf("\nList after sorting:\n");
traverse(personList);
// 15. **Reverse the linked list**
reverse(&personList);
printf("\nList after reversing:\n");
traverse(personList);
// 16. **Clear the list**
clear(&personList);
printf("\nList after clearing:\n");
traverse(personList);
return 0;
}
Here is the Generic circular singly linked list implementation in C++:
#include <iostream>
#include <string>
using namespace std;
// Node structure for circular singly linked list template
template <typename T>
struct Node {
T data;
Node* next;
// Constructor to create a new node
Node(T data) : data(data), next(nullptr) {}
};
// Insert at the beginning
template <typename T>
void insertAtBeginning(Node<T>*& head, T data) {
Node<T>* newNode = new Node<T>(data);
if (!head) {
head = newNode;
newNode->next = head;
} else {
Node<T>* temp = head;
while (temp->next != head)
temp = temp->next;
temp->next = newNode;
newNode->next = head;
head = newNode;
}
}
// Insert at the end
template <typename T>
void insertAtEnd(Node<T>*& head, T data) {
Node<T>* newNode = new Node<T>(data);
if (!head) {
head = newNode;
newNode->next = head;
} else {
Node<T>* temp = head;
while (temp->next != head)
temp = temp->next;
temp->next = newNode;
newNode->next = head;
}
}
// Function to insert a node after a given previous node
template <typename T>
void insertAfterNode(Node<T>* prevNode, T element) {
if (prevNode == nullptr) {
cout << "The given previous node cannot be NULL\n";
return;
}
Node<T>* newNode = new Node<T>(element);
newNode->next = prevNode->next;
prevNode->next = newNode;
}
// Function to insert a node before a given next node
template <typename T>
void insertBeforeNode(Node<T>*& head, Node<T>* nextNode, T element) {
if (head == nullptr) {
cout << "The list cannot be empty\n";
return;
}
if (nextNode == nullptr) {
cout << "The given next node cannot be NULL\n";
return;
}
Node<T>* newNode = new Node<T>(element);
if (head == nextNode) { // Insert before head
Node<T>* temp = head;
while (temp->next != head) {
temp = temp->next;
}
temp->next = newNode;
newNode->next = head;
head = newNode;
return;
}
Node<T>* temp = head;
do {
if (temp->next == nextNode) {
newNode->next = temp->next;
temp->next = newNode;
return;
}
temp = temp->next;
} while (temp != head);
cout << "The given next node is not found in the list\n";
delete newNode;
}
// Insert at a specific position
template <typename T>
void insertAtPosition(Node<T>*& head, T data, int position) {
Node<T>* newNode = new Node<T>(data);
if (position == 0) {
if (head == nullptr) {
head = newNode;
newNode->next = head; // Circular link
} else {
Node<T>* temp = head;
while (temp->next != head) {
temp = temp->next;
}
temp->next = newNode;
newNode->next = head;
head = newNode;
}
return;
}
Node<T>* temp = head;
for (int i = 0; i < position - 1; i++) {
temp = temp->next;
if (temp == head) {
cout << "Position out of bounds\n";
delete newNode;
return;
}
}
newNode->next = temp->next;
temp->next = newNode;
}
// Delete at the beginning
template <typename T>
void deleteAtBeginning(Node<T>*& head) {
if (!head) return;
if (head->next == head) {
delete head;
head = nullptr;
return;
}
Node<T>* temp = head;
Node<T>* last = head;
while (last->next != head)
last = last->next;
head = head->next;
last->next = head;
delete temp;
}
// Delete at the end
template <typename T>
void deleteAtEnd(Node<T>*& head) {
if (!head) return;
if (head->next == head) {
delete head;
head = nullptr;
return;
}
Node<T>* temp = head;
while (temp->next->next != head)
temp = temp->next;
delete temp->next;
temp->next = head;
}
// Delete at a specific position in a Circular Singly Linked List
template <typename T>
void deleteAtPosition(Node<T>*& head, int position) {
if (head == nullptr) {
cout << "List is empty\n";
return;
}
Node<T>* temp = head;
// If deleting the head node
if (position == 0) {
// If the list has only one node
if (head->next == head) {
delete head;
head = nullptr;
return;
}
// Find the last node to update its next pointer
Node<T>* last = head;
while (last->next != head) {
last = last->next;
}
last->next = head->next;
Node<T>* toDelete = head;
head = head->next;
delete toDelete;
return;
}
// Traverse to the node before the one to be deleted
Node<T>* prev = head;
for (int i = 0; i < position - 1 && prev->next != head; i++) {
prev = prev->next;
}
if (prev->next == head) {
cout << "Position out of bounds\n";
return;
}
// Delete the node
Node<T>* toDelete = prev->next;
prev->next = toDelete->next;
delete toDelete;
}
// check if the list is empty
template <typename T>
bool isEmpty(Node<T>* head) {
return head == nullptr;
}
// Traverse the list
template <typename T>
void traverse(Node<T>* head) {
if (!head) {
cout << "NULL\n";
return;
}
Node<T>* temp = head;
do {
cout << (temp->data).toString() << " -> ";
temp = temp->next;
} while (temp != head);
cout << "(head)\n";
}
// Search for an element in a Circular Singly Linked List
template <typename T>
bool search(Node<T>* head, T key) {
if (head == nullptr) return false; // Empty list
Node<T>* temp = head;
do {
if (temp->data == key)
return true;
temp = temp->next;
} while (temp != head); // Loop until we reach the head again
return false;
}
// Reverse a Circular Singly Linked List
template <typename T>
void reverse(Node<T>*& head) {
if (head == nullptr || head->next == head) return; // Empty list or single node
Node<T>* prev = nullptr;
Node<T>* current = head;
Node<T>* next = nullptr;
Node<T>* tail = head; // Keep track of the last node
do {
next = current->next;
current->next = prev;
prev = current;
current = next;
} while (current != head);
// Fix head and tail pointers
head->next = prev; // Make original head's next point to new head
head = prev; // Update head to new first element
}
// Get the size of a Circular Singly Linked List
template <typename T>
int size(Node<T>* head) {
if (head == nullptr) return 0; // Empty list
int count = 0;
Node<T>* temp = head;
do {
count++;
temp = temp->next;
} while (temp != head);
return count;
}
// Get an element at a specific index in a Circular Singly Linked List
template <typename T>
T get(Node<T>* head, int index) {
if (head == nullptr) throw out_of_range("Index out of range");
Node<T>* temp = head;
int count = 0;
do {
if (count == index)
return temp->data;
count++;
temp = temp->next;
} while (temp != head);
throw out_of_range("Index out of range");
}
// Set an element at a specific index in a Circular Singly Linked List
template <typename T>
void set(Node<T>* head, int index, T element) {
if (head == nullptr) throw out_of_range("Index out of range");
Node<T>* temp = head;
int count = 0;
do {
if (count == index) {
temp->data = element;
return;
}
count++;
temp = temp->next;
} while (temp != head);
throw out_of_range("Index out of range");
}
// Clear the list
template <typename T>
void clear(Node<T>*& head) {
if (!head) return;
Node<T>* temp = head;
Node<T>* nextNode;
do {
nextNode = temp->next;
delete temp;
temp = nextNode;
} while (temp != head);
head = nullptr;
}
// Function to merge two sorted circular linked lists
template <typename T>
void merge(Node<T>*& headRef, Node<T>* head1, Node<T>* head2) {
Node<T>* tempHead = nullptr, *last = nullptr;
Node<T>* first1 = head1, *first2 = head2;
//std::cout << "Starting merge...\n";
if (head1 == nullptr) {
//std::cout << "First list is empty. Returning a new node from the second list.\n";
Node<T>* newNode = new Node<T>(head2->data);
headRef = newNode;
head2 = head2->next;
if (head2 == first2) head2 = nullptr;
return;
}
if (head2 == nullptr) {
//std::cout << "Second list is empty. Returning a new node from the first list.\n";
Node<T>* newNode = new Node<T>(head1->data);
headRef = newNode;
head1 = head1->next;
if (head1 == first1) head1 = nullptr;
return;
}
//std::cout << "Both lists are non-empty. Merging...\n";
do {
Node<T>* newNode;
if (head1 && (head2 == nullptr || head1->data <= head2->data)) {
//std::cout << "Adding node from List 1: " << (head1->data).toString() << "\n";
newNode = new Node<T>(head1->data);
head1 = head1->next;
if (head1 == first1) {
head1 = nullptr;
}
} else {
//std::cout << "Adding node from List 2: " << (head2->data).toString() << "\n";
newNode = new Node<T>(head2->data);
head2 = head2->next;
if (head2 == first2) {
head2 = nullptr;
}
}
if (!tempHead) {
tempHead = newNode;
//std::cout << "New head node created: " << (tempHead->data).toString() << "\n";
} else {
last->next = newNode;
}
last = newNode;
} while (head1 != nullptr || head2 != nullptr);
// Make the list circular
last->next = tempHead;
headRef = tempHead;
//std::cout << "Merge completed. Circular list created with head: " << (headRef->data).toString() << "\n";
}
// Function to find the middle of a circular linked list
template <typename T>
void middle(Node<T>*& mid, Node<T>* head) {
if (head == nullptr || head->next == head) { // Check if list is empty or contains one node
mid = head;
return;
}
Node<T>* slow = head;
Node<T>* fast = head;
// Move fast two steps and slow one step
while (fast->next != head && fast->next->next != head) {
fast = fast->next->next;
slow = slow->next;
}
mid = slow; // Assign the slow pointer to mid (middle node)
}
template <typename T>
void sort(Node<T>*& headRef) {
// If the list is empty or contains a single node, no need to sort
if (headRef == nullptr || headRef->next == headRef) {
//std::cout << "List is empty or has only one node. No sorting needed.\n";
return;
}
//std::cout << "Starting sort...\n";
Node<T>* head = headRef;
Node<T>* mid = nullptr;
// Find the middle node
//std::cout << "Finding middle node...\n";
middle(mid, head);
//std::cout << "Middle node found: " << mid->data.toString() << "\n";
Node<T>* nextToMid = mid->next;
mid->next = head; // Break circularity for first half
Node<T>* secondHalf = nextToMid;
// Find the last node of the second half
Node<T>* last = secondHalf;
while (last->next != head)
last = last->next;
last->next = nextToMid; // Break circularity for second half
//std::cout << "Splitting list into two halves:\n";
//std::cout << "First half starts with: " << head->data.toString() << "\n";
//std::cout << "Second half starts with: " << secondHalf->data.toString() << "\n";
// Sort both halves recursively
//std::cout << "Sorting first half...\n";
sort(head);
//std::cout << "Sorting second half...\n";
sort(nextToMid);
// Merge the sorted halves
//std::cout << "Merging sorted halves...\n";
merge(headRef, head, nextToMid);
//std::cout << "Merge completed. Circular list created with head: " << headRef->data.toString() << "\n";
}
// Person class to demonstrate
class Person {
public:
string name;
int age;
Person(string name, int age) : name(name), age(age) {}
// Define < operator for sorting purposes (sort by name, then by age)
bool operator<=(const Person& other) const {
if (name == other.name) {
return age <= other.age; // If names are the same, sort by age
}
return name <= other.name; // Otherwise, sort by name
}
// Overload the equality operator to compare Person objects
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
string toString() const {
return "Person{name: " + name + ", age: " + to_string(age) + "}";
}
};
// Main function for testing
int main() {
// Create Person objects
Person alice("Alice", 30);
Person john("John", 19);
Person albert("Albert", 28);
Person robert("Robert", 20);
// Initialize the linked list
Node<Person>* head = nullptr;
// 1. Insert elements at the beginning
insertAtBeginning(head, alice);
insertAtBeginning(head, john);
// 2. Insert elements at the beginning
insertAtEnd(head, albert);
insertAtEnd(head, robert);
cout << "\nList after inserting elements:\n";
traverse(head);
// 3. Insert at a specific position
Person eve("Eve", 22);
insertAtPosition(head, eve, 2);
cout << "\nList after inserting at position 2:\n";
traverse(head);
// 4. Insert before a node (insert before the second node)
Node<Person>* secondNode = head->next; // Find the second node
Person george("George", 32);
insertBeforeNode(head, secondNode, george);
cout << "\nList after inserting before second node:\n";
traverse(head);
// 5. Insert after a node (insert after the second node)
Person joyce("Joyce", 27);
insertAfterNode(secondNode, joyce); // Insert after the second node
cout << "\nList after inserting after second node:\n";
traverse(head);
// 6. Delete the first node
deleteAtBeginning(head);
cout << "\nList after deleting first node:\n";
traverse(head);
// 7. Delete the last node
deleteAtEnd(head);
cout << "\nList after deleting last node:\n";
traverse(head);
// 8. Delete at a specific position
deleteAtPosition(head, 2);
cout << "\nList after deleting node at position 2:\n";
traverse(head);
// 9. Search for an element
bool found = search(head, albert);
cout << "\nSearch result for 'Albert': " << (found ? "Found" : "Not Found") << endl;
// 10. Get size of the list
cout << "\nSize of the list: " << size(head) << endl;
// 11. Check if list is empty
if (isEmpty(head)) {
cout << "The linked list is empty.\n";
} else {
cout << "The linked list is not empty.\n";
}
// 12. Get an element
try {
Person p = get(head, 2);
cout << "\nElement at index 2: " << p.toString() << endl;
} catch (const exception& e) {
cout << e.what() << endl;
}
// 13. Set (modify) an element
try {
Person updatedJohn("John", 25);
set(head, 1, updatedJohn);
cout << "\nList after modifying index 1:\n";
traverse(head);
} catch (const exception& e) {
cout << e.what() << endl;
}
// 14. Sort the linked list (by name first, then by age)
sort(head);
cout << "\nList after sorting:" << endl;
traverse(head);
// 15. Reverse the list
reverse(head);
cout << "\nReversed List:" << endl;
traverse(head);
// 16. Clear the list
clear(head);
cout << "\nList after clearing:" << endl;
traverse(head); // Should print NULL, as the list is cleared
return 0;
}
Here is the Generic circular singly linked list implementation in Java:
class CircularLinkedList<T> {
// Node structure for circular singly linked list
static class Node<T> {
T data;
Node<T> next;
// Constructor to create a new node
Node(T data) {
this.data = data;
this.next = null;
}
}
// Insert at the beginning
public static <T> Node<T> insertAtBeginning(Node<T> tail, T data) {
Node<T> newNode = new Node<>(data);
if (tail == null) {
newNode.next = newNode; // Point to itself
return newNode;
}
newNode.next = tail.next;
tail.next = newNode;
return tail;
}
// Insert at the end
public static <T> Node<T> insertAtEnd(Node<T> tail, T data) {
Node<T> newNode = new Node<>(data);
if (tail == null) {
newNode.next = newNode;
return newNode;
}
newNode.next = tail.next;
tail.next = newNode;
return newNode; // New tail
}
// Insert at a specific position
public static <T> Node<T> insertAtPosition(Node<T> tail, T data, int position) {
if (tail == null || position == 0) {
return insertAtBeginning(tail, data);
}
Node<T> newNode = new Node<>(data);
Node<T> temp = tail.next;
for (int i = 0; i < position - 1 && temp != tail; i++) {
temp = temp.next;
}
newNode.next = temp.next;
temp.next = newNode;
if (temp == tail) {
return newNode; // New tail
}
return tail;
}
// Function to insert a new node after a given previous node
public static <T> void insertAfterNode(Node<T> prevNode, T data) {
if (prevNode == null) {
System.out.println("The given previous node cannot be NULL.");
return;
}
Node<T> newNode = new Node<>(data);
newNode.next = prevNode.next;
prevNode.next = newNode;
}
// Function to insert a new node before a given next node
public static <T> Node<T> insertBeforeNode(Node<T> head, Node<T> nextNode, T data) {
if (head == null) {
System.out.println("The list cannot be empty.");
return null;
}
if (nextNode == null) {
System.out.println("The given next node cannot be NULL.");
return head;
}
Node<T> newNode = new Node<>(data);
// If inserting before the head, update head reference
if (head == nextNode) {
Node<T> temp = head;
while (temp.next != head) {
temp = temp.next;
}
temp.next = newNode; // Update last node's next pointer
newNode.next = head;
return newNode; // New node becomes the head
}
// Find the node just before nextNode
Node<T> temp = head;
while (temp.next != head && temp.next != nextNode) {
temp = temp.next;
}
if (temp.next != nextNode) {
System.out.println("The given next node is not found in the list.");
return head;
}
newNode.next = temp.next;
temp.next = newNode;
return head;
}
// Delete at the beginning
public static <T> Node<T> deleteAtBeginning(Node<T> tail) {
if (tail == null) {
System.out.println("List is empty");
return null;
}
if (tail.next == tail) { // Single node case
return null;
}
tail.next = tail.next.next;
return tail;
}
// Delete at the end
public static <T> Node<T> deleteAtEnd(Node<T> tail) {
if (tail == null) {
System.out.println("List is empty");
return null;
}
if (tail.next == tail) { // Single node case
return null;
}
Node<T> temp = tail.next;
while (temp.next != tail) {
temp = temp.next;
}
temp.next = tail.next; // Skip tail node
return temp; // New tail
}
// Delete at a specific position (Generic)
public static <T> Node<T> deleteAtPosition(Node<T> tail, int position) {
if (tail == null) {
return null;
}
if (position == 0) {
return deleteAtBeginning(tail);
}
Node<T> temp = tail.next;
for (int i = 0; i < position - 1 && temp.next != tail.next; i++) {
temp = temp.next;
}
if (temp.next == tail.next) {
return tail; // Position out of bounds, return unchanged tail
}
// If deleting the tail node, update tail reference
if (temp.next == tail) {
tail = temp;
}
temp.next = temp.next.next;
return tail;
}
// Function to get an element at a specific index (0-based)
public static <T> T get(Node<T> head, int index) {
if (head == null) {
System.out.println("List is empty");
return null;
}
Node<T> temp = head;
int count = 0;
do {
if (count == index) {
return temp.data;
}
count++;
temp = temp.next;
} while (temp != head);
System.out.println("Index out of range");
return null;
}
// Function to set an element at a specific index (0-based)
public static <T> void set(Node<T> head, int index, T newValue) {
if (head == null) {
System.out.println("List is empty");
return;
}
Node<T> temp = head;
int count = 0;
do {
if (count == index) {
temp.data = newValue;
return;
}
count++;
temp = temp.next;
} while (temp != head);
System.out.println("Index out of range");
}
// check if the list is empty
public static <T> boolean isEmpty(Node<T> head) {
return head == null;
}
// Search for an element
public static <T> boolean search(Node<T> tail, T key) {
if (tail == null) return false;
Node<T> temp = tail.next;
do {
if (temp.data.equals(key)) {
return true;
}
temp = temp.next;
} while (temp != tail.next);
return false;
}
// Get the size of the list
public static <T> int size(Node<T> tail) {
if (tail == null) return 0;
int count = 0;
Node<T> temp = tail.next;
do {
count++;
temp = temp.next;
} while (temp != tail.next);
return count;
}
// Traverse the list
public static <T> void traverse(Node<T> tail) {
if (tail == null) {
System.out.println("NULL");
return;
}
Node<T> temp = tail.next;
do {
System.out.print(temp.data + " -> ");
temp = temp.next;
} while (temp != tail.next);
System.out.println("(back to head)");
}
public static <T> Node<T> reverse(Node<T> head) {
if (head == null || head.next == head)
return head; // Empty list or single node remains the same
Node<T> prev = null;
Node<T> current = head;
Node<T> next = null;
Node<T> last = head;
// Find the last node
while (last.next != head)
last = last.next;
do {
next = current.next; // Store next node
current.next = prev; // Reverse pointer
prev = current; // Move prev forward
current = next; // Move current forward
} while (current != head);
// Adjust pointers to maintain circular nature
head.next = prev; // Original head now points to the new last node
last.next = prev; // Last node points to the new head
return prev; // New head of the reversed circular list
}
// Function to find the middle node of a circular linked list
public static <T> Node<T> middle(Node<T> head) {
if (head == null || head.next == head) return head;
Node<T> slow = head, fast = head;
while (fast.next != head && fast.next.next != head) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
// Function to sort a circular linked list using merge sort (requires Comparable<T>)
public static <T extends Comparable<T>> Node<T> sort(Node<T> head) {
if (head == null || head.next == head) return head;
Node<T> mid = middle(head);
Node<T> secondHalf = mid.next;
mid.next = head; // Break circularity for the first half
// Find last node of second half and break circularity
Node<T> temp = secondHalf;
while (temp.next != head) temp = temp.next;
temp.next = secondHalf;
// Recursively sort both halves
Node<T> firstSorted = sort(head);
Node<T> secondSorted = sort(secondHalf);
// Merge both halves
return merge(firstSorted, secondSorted);
}
public static <T extends Comparable<T>> Node<T> merge(Node<T> head1, Node<T> head2) {
if (head1 == null) return head2;
if (head2 == null) return head1;
Node<T> tempHead = null, last = null;
Node<T> first1 = head1, first2 = head2;
do {
Node<T> newNode;
if (head1 != null && (head2 == null || head1.data.compareTo(head2.data) <= 0)) {
newNode = new Node<>(head1.data);
head1 = head1.next;
if (head1 == first1) head1 = null;
} else {
newNode = new Node<>(head2.data);
head2 = head2.next;
if (head2 == first2) head2 = null;
}
if (tempHead == null) {
tempHead = newNode;
} else {
last.next = newNode;
}
last = newNode;
} while (head1 != null || head2 != null);
// Make the list circular
last.next = tempHead;
return tempHead;
}
// Clear the list
public static <T> Node<T> clear(Node<T> head) {
if (head == null) return null; // If the list is already empty, return null
Node<T> current = head;
do {
Node<T> next = current.next; // Save reference to next node
current.next = null; // Break the link to the next node
current = next; // Move to the next node
} while (current != head); // Stop when we've looped back to the head
return null; // Return null to indicate the list is empty
}
// Person class
static class Person implements Comparable<Person> {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name: " + name + ", age: " + age + "}";
}
@Override
public int compareTo(Person other) {
// Compare by name first, then by age
int nameComparison = this.name.compareTo(other.name);
if (nameComparison != 0) {
return nameComparison;
}
return Integer.compare(this.age, other.age);
}
}
// Main method for testing
public static void main(String[] args) {
// Create Person objects
Person alice = new Person("Alice", 30);
Person john = new Person("John", 19);
Person albert = new Person("Albert", 28);
Person robert = new Person("Robert", 20);
// Initialize the linked list
Node<Person> head = null;
// 1. Insert elements at the beginning
head = insertAtBeginning(head, alice);
head = insertAtBeginning(head, john);
// 2. Insert elements at the end
head = insertAtEnd(head, albert);
head = insertAtEnd(head, robert);
System.out.println("\nList after inserting elements:");
traverse(head);
// 3. Insert at a specific position
Person eve = new Person("Eve", 22);
head = insertAtPosition(head, eve, 2);
System.out.println("\nList after inserting at position 2:");
traverse(head);
// 4. Insert before a node (insert before the second node)
Node<Person> secondNode = head.next; // Find the second node
head = insertBeforeNode(head, secondNode, eve);
System.out.println("\nList after inserting before second node:");
traverse(head);
// 5. Insert after a node (insert after the second node)
insertAfterNode(secondNode, eve); // Insert after the second node
System.out.println("\nList after inserting after second node:");
traverse(head);
// 6. Delete the first node
head = deleteAtBeginning(head);
System.out.println("\nList after deleting first node:");
traverse(head);
// 7. Delete the last node
head = deleteAtEnd(head);
System.out.println("\nList after deleting last node:");
traverse(head);
// 8. Delete at a specific position
head = deleteAtPosition(head, 2);
System.out.println("\nList after deleting node at position 2:");
traverse(head);
// 9. Search for an element
boolean found = search(head, albert);
System.out.println("\nSearch result for 'Albert': " + (found ? "Found" : "Not Found"));
// 10. Get size of the list
System.out.println("\nSize of the list: " + size(head));
// 11. Check if list is empty
if (isEmpty(head)) {
System.out.println("The list is empty.");
} else {
System.out.println("The list is not empty.");
}
// 12. Get an element
try {
Person p = get(head, 2);
System.out.println("\nElement at index 2: " + p.toString());
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 13. Set (modify) an element
try {
Person updatedJohn = new Person("John", 25);
set(head, 1, updatedJohn);
System.out.println("\nList after modifying index 1:");
traverse(head);
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 14. Sort the linked list (by name first, then by age)
head = sort(head);
System.out.println("\nList after sorting:");
traverse(head);
// 15. Reverse the list
head = reverse(head);
System.out.println("\nList after reversing:");
traverse(head);
// 16. Clear the list
head = clear(head);
System.out.println("After clearing the list:");
traverse(head); // This should print "NULL" as the list is now empty
}
}
Here is the Generic circular singly linked list implementation in C#:
using System;
class Node<T>
{
public T Data;
public Node<T> Next;
public Node(T data)
{
Data = data;
Next = null;
}
}
class Program
{
// Insert at beginning
static Node<T> InsertAtBeginning<T>(Node<T> head, T data)
{
Node<T> newNode = new Node<T>(data);
if (head == null)
{
newNode.Next = newNode; // Point to itself in a circular list
return newNode;
}
Node<T> temp = head;
while (temp.Next != head) temp = temp.Next; // Find the last node
temp.Next = newNode;
newNode.Next = head;
return newNode;
}
// Insert at end
static Node<T> InsertAtEnd<T>(Node<T> head, T data)
{
Node<T> newNode = new Node<T>(data);
if (head == null)
{
newNode.Next = newNode;
return newNode;
}
Node<T> temp = head;
while (temp.Next != head) temp = temp.Next; // Find the last node
temp.Next = newNode;
newNode.Next = head;
return head;
}
// Insert at position
static Node<T> InsertAtPosition<T>(Node<T> head, T data, int position)
{
if (position == 0) return InsertAtBeginning(head, data);
Node<T> newNode = new Node<T>(data);
Node<T> temp = head;
for (int i = 0; i < position - 1 && temp.Next != head; i++) temp = temp.Next;
newNode.Next = temp.Next;
temp.Next = newNode;
return head;
}
// Insert before node
static Node<T> InsertBeforeNode<T>(Node<T> head, Node<T> targetNode, T data)
{
if (head == null || targetNode == null) return head;
if (head == targetNode) return InsertAtBeginning(head, data);
Node<T> temp = head;
do
{
if (temp.Next == targetNode)
{
Node<T> newNode = new Node<T>(data) { Next = targetNode };
temp.Next = newNode;
return head;
}
temp = temp.Next;
} while (temp != head);
return head; // Target node not found
}
// Insert after node
static void InsertAfterNode<T>(Node<T> node, T data)
{
if (node == null) return;
Node<T> newNode = new Node<T>(data) { Next = node.Next };
node.Next = newNode;
}
// Delete at beginning
static Node<T> DeleteAtBeginning<T>(Node<T> head)
{
if (head == null) return null;
if (head.Next == head) return null; // Only one node
Node<T> temp = head;
while (temp.Next != head) temp = temp.Next; // Find last node
temp.Next = head.Next;
return head.Next;
}
// Delete at end
static Node<T> DeleteAtEnd<T>(Node<T> head)
{
if (head == null) return null;
if (head.Next == head) return null; // Only one node
Node<T> temp = head;
while (temp.Next.Next != head) temp = temp.Next; // Find second last node
temp.Next = head;
return head;
}
// Delete at a specific position
static Node<T> DeleteAtPosition<T>(Node<T> head, int position)
{
if (head == null) return null; // Empty list
Node<T> temp = head, prev = null;
// If deleting the head node
if (position == 0)
{
if (head.Next == head) // Only one node in the list
return null;
// Find the last node to update its `Next` pointer
while (temp.Next != head)
temp = temp.Next;
temp.Next = head.Next; // Point last node to the new head
return head.Next;
}
// Traverse to the position
int count = 0;
do
{
prev = temp;
temp = temp.Next;
count++;
} while (temp != head && count < position);
// If position is out of bounds
if (count != position)
{
Console.WriteLine("Position out of bounds");
return head;
}
prev.Next = temp.Next; // Remove node by updating pointer
return head;
}
// Search for an element in a circular singly linked list
static bool Search<T>(Node<T> head, T key)
{
if (head == null) return false; // Handle case of empty list
Node<T> temp = head;
do
{
if (temp.Data.Equals(key)) return true;
temp = temp.Next;
} while (temp != head); // Stop when we've looped back to the head
return false;
}
// Get size of a circular singly linked list
static int Size<T>(Node<T> head)
{
if (head == null) return 0; // Handle case of empty list
int count = 0;
Node<T> temp = head;
do
{
count++;
temp = temp.Next;
} while (temp != head); // Stop when we've looped back to the head
return count;
}
// Check if the circular singly linked list is empty
static bool IsEmpty<T>(Node<T> head)
{
return head == null;
}
// Get an element at a specific index in a circular singly linked list
static T Get<T>(Node<T> head, int index)
{
if (head == null) throw new Exception("List is empty");
int count = 0;
Node<T> temp = head;
do
{
if (count == index) return temp.Data;
count++;
temp = temp.Next;
} while (temp != head); // Stop when we've looped back to the head
throw new Exception("Index out of range");
}
// Set (modify) an element at a specific index in a circular singly linked list
static void Set<T>(Node<T> head, int index, T newValue)
{
if (head == null) throw new Exception("List is empty");
int count = 0;
Node<T> temp = head;
do
{
if (count == index)
{
temp.Data = newValue;
return;
}
count++;
temp = temp.Next;
} while (temp != head); // Stop when we've looped back to the head
throw new Exception("Index out of range");
}
// Traverse the circular list
static void Traverse<T>(Node<T> head)
{
if (head == null)
{
Console.WriteLine("List is empty.");
return;
}
Node<T> temp = head;
do
{
Console.Write(temp.Data + " -> ");
temp = temp.Next;
} while (temp != head);
Console.WriteLine("(back to head)");
}
// Reverse a circular singly linked list
static Node<T> Reverse<T>(Node<T> head)
{
if (head == null || head.Next == head) return head; // Handle empty or single-element list
Node<T> prev = null;
Node<T> current = head;
Node<T> next = null;
// Traverse the list and reverse the links
do
{
next = current.Next; // Save the next node
current.Next = prev; // Reverse the current node's link
prev = current; // Move prev to the current node
current = next; // Move to the next node
} while (current != head); // Stop when we've looped back to the head
// After the loop, `prev` is pointing to the new head
head = prev; // Update the head reference to the new first node
// The last node's `Next` should point to the new head
current.Next = head; // The previous tail should point to the new head
return head; // Return the new head
}
public static Node<T> Merge<T>(Node<T> head1, Node<T> head2) where T : IComparable<T>
{
if (head1 == null) return head2;
if (head2 == null) return head1;
Node<T> dummy = new Node<T>(default(T)); // Temporary dummy node
Node<T> tail = dummy;
Node<T> first1 = head1, first2 = head2;
do
{
Node<T> newNode;
if (head1 != null && (head2 == null || head1.Data.CompareTo(head2.Data) <= 0))
{
newNode = new Node<T>(head1.Data);
head1 = head1.Next;
if (head1 == first1) head1 = null;
}
else
{
newNode = new Node<T>(head2.Data);
head2 = head2.Next;
if (head2 == first2) head2 = null;
}
tail.Next = newNode;
tail = newNode;
} while (head1 != null || head2 != null);
// Make the merged list circular
tail.Next = dummy.Next;
return dummy.Next;
}
public static Node<T> Middle<T>(Node<T> head) where T : IComparable<T>
{
if (head == null || head.Next == head) return head;
Node<T> slow = head, fast = head;
while (fast.Next != head && fast.Next.Next != head)
{
fast = fast.Next.Next;
slow = slow.Next;
}
return slow;
}
public static Node<T> Sort<T>(Node<T> head) where T : IComparable<T>
{
if (head == null || head.Next == head) return head;
Node<T> mid = Middle(head);
Node<T> secondHalf = mid.Next;
mid.Next = head; // Break circularity for the first half
// Find last node of second half and break circularity
Node<T> temp = secondHalf;
while (temp.Next != head) temp = temp.Next;
temp.Next = secondHalf;
// Recursively sort both halves
Node<T> firstSorted = Sort(head);
Node<T> secondSorted = Sort(secondHalf);
// Merge both halves
return Merge(firstSorted, secondSorted);
}
public static Node<T> Clear<T>(Node<T> head)
{
if (head == null) return null; // If the list is already empty, return null
Node<T> current = head;
do
{
Node<T> next = current.Next; // Save reference to next node
current.Next = null; // Break the link to the next node
current = next; // Move to the next node
} while (current != head); // Stop when we've looped back to the head
return null; // Return null to indicate the list is empty
}
static void Main()
{
// Create Person objects
Person alice = new Person("Alice", 30);
Person john = new Person("John", 19);
Person albert = new Person("Albert", 28);
Person robert = new Person("Robert", 20);
// Initialize the linked list
Node<Person> head = null;
// 1. Insert elements at the beginning
head = InsertAtBeginning(head, alice);
head = InsertAtBeginning(head, john);
// 2. Insert elements at the end
head = InsertAtEnd(head, albert);
head = InsertAtEnd(head, robert);
Console.WriteLine("\nList after inserting elements:");
Traverse(head);
// 3. Insert at a specific position
Person eve = new Person("Eve", 22);
head = InsertAtPosition(head, eve, 2);
Console.WriteLine("\nList after inserting at position 2:");
Traverse(head);
// 4. Insert before a node (insert before the second node)
Node<Person> secondNode = head.Next; // Find the second node
Person jack = new Person("Jack", 29);
head = InsertBeforeNode(head, secondNode, jack);
Console.WriteLine("\nList after inserting before second node:");
Traverse(head);
// 5. Insert after a node (insert after the second node)
InsertAfterNode(secondNode, eve); // Insert after the second node
Console.WriteLine("\nList after inserting after second node:");
Traverse(head);
// 6. Delete the first node
head = DeleteAtBeginning(head);
Console.WriteLine("\nList after deleting first node:");
Traverse(head);
// 7. Delete the last node
head = DeleteAtEnd(head);
Console.WriteLine("\nList after deleting last node:");
Traverse(head);
// 8. Delete node at position 2
head = DeleteAtPosition(head, 2);
Console.WriteLine("\nList after deleting at position 2:");
Traverse(head);
// 9. Search for an element
bool found = Search(head, albert);
Console.WriteLine("\nSearch result for 'Albert': " + (found ? "Found" : "Not Found"));
// 10. Get size of the list
Console.WriteLine("\nSize of the list: " + Size(head));
// 11. Check if the list is empty
if (IsEmpty(head))
{
Console.WriteLine("The list is empty.");
}
else
{
Console.WriteLine("The list is not empty.");
}
// 12. Get an element
try
{
Person p = Get(head, 2);
Console.WriteLine("\nElement at index 2: " + p.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
// 13. Set (modify) an element
try
{
Person updatedJohn = new Person("John", 25);
Set(head, 1, updatedJohn);
Console.WriteLine("\nList after modifying index 1:");
Traverse(head);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
// 14. Sort the linked list (by name first, then by age)
head = Sort(head);
Console.WriteLine("\nList after sorting:");
Traverse(head);
// 15. Reverse the list
head = Reverse(head);
Console.WriteLine("\nList after reversing:");
Traverse(head);
// 16. Clear the list
head = Clear(head);
Console.WriteLine("\nList after clearing:");
Traverse(head);
}
}
class Person : IComparable<Person>
{
public string Name;
public int Age;
public Person(string name, int age) { Name = name; Age = age; }
public int CompareTo(Person other)
{
// Sort by Name, then Age
return Name.CompareTo(other.Name) != 0 ? Name.CompareTo(other.Name) : Age.CompareTo(other.Age);
}
public override string ToString() => $"Person{{name: {Name}, age: {Age}}}";
}