In this article, we will discuss how to detect and remove Loop in a Linked List in C++ with different methods.
Create a function called detectAndRemoveLoop that verifies whether a given Linked List has a loop. After that, it removes the Loop and returns true if it does. It returns false if there isn't a loop in the List. A linked list with a loop is depicted in the diagram below. The List below must be changed to 1->2->3->4->5->NULL using the detectAndRemoveLoop method.
Write a C function to detect a loop in a linked list.
- We must first identify the Loop before attempting to remove it. Loops can be found using the methods discussed in the section above. All we have to do to end the Loop is obtain a pointer to the Loop's final node. Consider the node in the diagram above with the value 5. Once we know which node is the final, we may make the next node in this chain NULL to end the Loop.
- We may quickly apply the hashing or visited node approaches to obtain the pointer to the last node. The concept is straightforward: the final node is the first node whose next has already been visited (or hashed).
- The Floyd Cycle Detection technique can be used to find and get rid of the Loop as well. The slow and fascpp tutorialers in Floyd's algorithm come together at a loop node. This loop node can be used to get rid of the cycle. When Floyd's technique detects loops, two distinct approaches exist to break the Loop.
Method 1: (Check each one separately)
Floyd's Cycle detection process is known to come to an end when the fast and slow pointers collide at the same location. Additionally, we are aware that this common point is one of the loop nodes (2, 3, 4, or 5 in the image above). Put this location in a pointer variable, like ptr2. After that, starting at the head of the Linked List, determine if each node is reachable from ptr2 by checking each one individually. When a node in a linked list is reachable, we can obtain the pointer to the preceding node of that node, indicating that this node represents the beginning of the Loop.
Output:
Linked List after removing Loop
50 20 15 4 10
Method 2: (Better Solution)
- This technique also requires Floyd's Cycle detection
- Get the pointer to a loop node by utilizing Floyd's Cycle detection technique to find a loop.
- Count how many nodes are in the Loop. Let k be the count.
- One pointer should be fixed to the head and the other to a kth node from the head.
- The pointers will collide at the Loop's starting node if we move them both at the same speed.
- Obtain a pointer to the Loop's final node and make the next one NULL.
Program:
Let us take an example to illustrate how to detect and remove a loop in a linked list in C++.
#include <bits/stdc++.h>
using namespace std;
/* Link list node */
struct Node {
int data;
struct Node* next;
};
/* Function to remove Loop. */
void removeLoop(struct Node*, struct Node*);
/* This Function detects and removes Loop in the
List
If Loop was there in the List, then it returns 1,
otherwise returns 0 */
int detectAndRemoveLoop(struct Node* list)
{
struct Node *slow_p = list, *fast_p = list;
// Iterate and find if Loop exists or not
while (slow_p && fast_p && fast_p->next) {
slow_p = slow_p->next;
fast_p = fast_p->next->next;
/* If slow_p and fast_p meet at some point, then there is a loop */
if (slow_p == fast_p) {
removeLoop(slow_p, list);
/* Return 1 to indicate that Loop is found */
return 1;
}
}
/* Return 0 to indicate that there is no loop*/
return 0;
}
/* Function to remove Loop.
loop_node --> Pointer to one of the loop nodes
head --> Pointer to the start node of the linked list */
void removeLoop(struct Node* loop_node, struct Node* head)
{
struct Node* ptr1 = loop_node;
struct Node* ptr2 = loop_node;
// Count the number of nodes in the Loop
unsigned int k = 1, i;
while (ptr1->next != ptr2) {
ptr1 = ptr1->next;
k++;
}
// Fix one pointer to head
ptr1 = head;
// And the other pointer to k nodes after head
ptr2 = head;
for (i = 0; i < k; i++)
ptr2 = ptr2->next;
/* Move both pointers at the same pace,
they will meet at Loop starting node */
while (ptr2 != ptr1) {
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}
// Get a pointer to the last node
while (ptr2->next != ptr1)
ptr2 = ptr2->next;
/* Set the next node of the Loop ending node
to fix the Loop */
ptr2->next = NULL;
}
/* Function to print linked List */
void printList(struct Node* node)
{
// Print the List after loop removal
while (node != NULL) {
cout << node->data << " ";
node = node->next;
}
}
struct Node* newNode(int key)
{
struct Node* temp = new Node();
temp->data = key;
temp->next = NULL;
return temp;
}
// Driver Code
int main()
{
struct Node* head = newNode(35);
head->next = newNode(10);
head->next->next = newNode(12);
head->next->next->next = newNode(54);
head->next->next->next->next = newNode(5);
/* Create a loop for testing */
head->next->next->next->next->next = head->next->next;
detectAndRemoveLoop(head);
cout << "Linked List after removing loop \n";
printList(head);
return 0;
}
Output:
Complexity Analysis:
Time Complexity: O(N) , Where N is the number of nodes in the tree
Auxiliary Space: O(1)
Method 3: (Without Counting Nodes in Loop)
The number of nodes in the Loop does not need to be counted. After identifying the Loop, if we move the fast and slow pointers at the same speed until the fascpp tutorialers don't meet, they will collide at the beginning of the Loop.
How does this work?
Let Floyd's Cycle detection algorithm lead to a point where slow and fast will collide. The scenario when the cycle is discovered is depicted in the diagram below.
We can conclude from the above diagram.
Distance traveled by fascpp tutorialer = 2 * (Distance traveled by slow pointer)
(m + n*x + k) = 2*(m + n*y + k)
Note that before meeting the point shown above, fast was moving at twice the speed.
x --> Number of complete cyclic rounds made by
fascpp tutorialer before they meet the first time
y --> Number of complete cyclic rounds made by
slow pointer before they meet the first time
From the above equation, we can conclude below
m + k = (x-2y)*n
Which means m+k is a multiple of n.
Thus we can write m + k = i*n or m = i*n - k.
Hence, the distance moved by the slow pointer: m, is equal to the distance moved by the fascpp tutorialer:
i*n - k or (i-1)*n + n - k (cover the loop completely i-1 times and start from n-k).
As a result, if we start moving both pointers again at the same speed, one pointer (let's call it slow) will start from the head node of the linked List while the other (let's call it fast) will start from the meeting point. The fascpp tutorialer would have also gone m steps because they are now going at the same speed when the slow pointer reaches the beginning of the Loop (having made m steps). They would collide at the beginning because the fascpp tutorialer starts from k, and m+k is a multiple of n.
Program:
// C++ program to detect and remove Loop
#include <bits/stdc++.h>
using namespace std;
struct Node {
int key;
struct Node* next;
};
Node* newNode(int key)
{
Node* temp = new Node;
temp->key = key;
temp->next = NULL;
return temp;
}
// A utility function to print a linked list
void printList(Node* head)
{
while (head != NULL) {
cout << head->key << " ";
head = head->next;
}
cout << endl;
}
//Function to detect and remove Loop in a linked list that
// may contain Loop
void detectAndRemoveLoop(Node* head)
{
// If the List is empty or has only one node without Loop
if (head == NULL || head->next == NULL)
return;
Node *slow = head, *fast = head;
// Move slow and fast 1 and 2 steps ahead, respectively.
slow = slow->next;
fast = fast->next->next;
// Search for Loop using slow and fascpp tutorialers
while (fast && fast->next) {
if (slow == fast)
break;
slow = slow->next;
fast = fast->next->next;
}
/* If loop exists */
if (slow == fast) {
slow = head;
//This check is needed when slow and fast both meet
// at the head of the LL eg: 1->2->3->4->5 and then
// 5->next = 1, i.e the head of the LL
if (slow == fast)
while (fast->next != slow)
fast = fast->next;
else {
while (slow->next != fast->next) {
slow = slow->next;
fast = fast->next;
}
}
/* since fast->next is the looping point */
fast->next = NULL; /* remove loop */
}
}
/* Driver program to test above Function*/
int main()
{
Node* head = newNode(35);
head->next = head;
head->next = newNode(10);
head->next->next = newNode(54);
head->next->next->next = newNode(5);
head->next->next->next->next = newNode(10);
/* Create a loop for testing */
head->next->next->next->next->next = head;
detectAndRemoveLoop(head);
printf("Linked List after removing loop \n");
printList(head);
return 0;
}
Output:
Complexity Analysis:
Time Complexity: O(N), Where N is the number of nodes in the tree
Auxiliary Space: O(1)
Method 4: Hashing (Hash the linked list nodes' addresses)
We can check to see if an element already exists in the map by hashing the addresses of the linked list nodes in an unordered map. We must set the last node's nexcpp tutorialer to NULL because if it exists, we have reached a node that already exists by a cycle.
Program:
// C++ program to detect and remove Loop
#include <bits/stdc++.h>
using namespace std;
struct Node {
int key;
struct Node* next;
};
Node* newNode(int key)
{
Node* temp = new Node;
temp->key = key;
temp->next = NULL;
return temp;
}
// A utility function to print a linked list
void printList(Node* head)
{
while (head != NULL) {
cout << head->key << " ";
head = head->next;
}
cout << endl;
}
//Function to detect and remove the loop
// in a linked list that may contain Loop
void hashAndRemove(Node* head)
{
// hash map to hash addresses of the linked list nodes
unordered_map<Node*, int> node_map;
// pointer to the last node
Node* last = NULL;
while (head != NULL) {
//If node not present in the map, insert it in the map
if (node_map.find(head) == node_map.end()) {
node_map[head]++;
last = head;
head = head->next;
}
//If present, it is a cycle; make the last node's nexcpp tutorialer NULL
else {
last->next = NULL;
break;
}
}
}
/* Driver program to test above Function*/
int main()
{
Node* head = newNode(35);
head->next = head;
head->next = newNode(10);
head->next->next = newNode(54);
head->next->next->next = newNode(5);
head->next->next->next->next = newNode(10);
/* Create a loop for testing */
head->next->next->next->next->next = head->next->next;
// printList(head);
hashAndRemove(head);
printf("Linked List after removing loop \n");
printList(head);
return 0;
}
Output:
Complexity Analysis:
Time Complexity: O(N), Where N is the number of nodes in the tree.
Auxiliary Space: O(N), Where N is the number of nodes in the tree (due to hashing).