Remove Loop
#include <bits/stdc++.h> // Common includesusing namespace std; // Standard namespace
// Node Class: Defines structure of a linked list nodeclass Node {public: int data; // Data storage Node* next; // Pointer to next node
// Node Constructor Node(int data) { this->data = data; this->next = NULL; // Initialize next as NULL }};
// printList: Prints all elements in the listvoid printList(Node* head) { if(head == NULL) { cout << "List is Empty!" << endl; return; }
cout << "Singly List : "; while(head != NULL) { cout << head->data << " "; // Print data head = head->next; // Move to next node } cout << endl;}
// insertAtHead: Adds node to the beginningvoid insertAtHead(Node* &head, int data) { Node *temp = new Node(data); // Create new node temp->next = head; // New node points to old head head = temp; // Head updates to new node}
// insertAtTail: Adds node to the endvoid insertAtTail(Node* &tail, int data) { Node *temp = new Node(data); // Create new node tail->next = temp; // Old tail points to new node tail = temp; // Tail updates to new node}
// insertAtMiddle: Inserts node at a specific positionvoid insertAtMiddle(Node* &head, Node* &tail, int data, int pos) { if(pos == 1) { // Special case: insert at head insertAtHead(head, data); return; }
Node *temp = head; // Traverse pointer while(temp != NULL && pos > 2) { // Find node BEFORE insertion point temp = temp->next; pos--; }
if(temp==NULL || pos<=0) { // Invalid position check cout << "Invalid Position!" << endl; return; }
Node *insertNode = new Node(data); // Create node to insert insertNode->next = temp->next; // New node points to temp's next temp->next = insertNode; // Temp points to new node
if(insertNode->next == NULL) { // Update tail if inserted at end tail = insertNode; }}
// deletePosition: Deletes node at a specific positionvoid deletePosition(Node* &head, int pos) { Node *temp = head; // Pointer for deletion/traversal if(pos == 1) { // Special case: delete head head = head->next; delete temp; // Free memory return; }
while(temp!=NULL && pos > 2) { // Find node BEFORE deletion point temp = temp->next; pos--; }
if(temp==NULL || temp->next==NULL || pos<=0) { // Invalid position check cout << "Invalid Position!" << endl; return; }
Node* target = temp->next; // Node to be deleted temp->next = target->next; // Bypass target node delete target; // Free memory}
// deleteValue: Deletes first occurrence of a specific valuevoid deleteValue(Node* &head, int val) { Node* temp = head->next; // Current pointer Node* prev = head; // Previous pointer
if(head->data == val) { // Special case: delete head by value head = head->next; delete prev; // Free old head return; }
// Traverse to find the value while(temp!=NULL) { if(temp->data == val) { val = INT_MIN; // Sentinel to mark value found break; } prev = temp; // Move prev temp = temp->next; // Move temp }
if(prev->next==NULL || val!=INT_MIN) { // Value not found cout << "Value Not Found!" << endl; return; }
prev->next = temp->next; // Bypass target node delete temp; // Free memory}
// floydDetectLoop: Detects if a cycle (loop) is present using Floyd's Cycle-Finding Algorithm (Tortoise and Hare)bool floydDetectLoop(Node* head) { if(head == NULL) { // Empty list has no loop return false; }
Node* slow = head; // Slow pointer (moves 1 step at a time) Node* fast = head; // Fast pointer (moves 2 steps at a time)
// Traverse the list with two pointers while(slow != NULL && fast != NULL) { fast = fast->next; // Fast moves 1 step slow = slow->next; // Slow moves 1 step
if(fast != NULL) { // Check if fast is not NULL before moving it again fast = fast->next; // Fast moves another step }
if(slow == fast) { // If pointers meet, a loop is detected return true; } }
return false; // Fast pointer reached NULL, no loop found}
// beginningPoint: Finds the starting node of a loop in a linked list (assumes a loop exists)Node* beginningPoint(Node* head) { if(head == NULL) { // Empty list, no loop, no beginning point return head; }
Node* slow = head; // Slow pointer (1 step) Node* fast = head; // Fast pointer (2 steps)
// STEP 1: Find Intersection Node (where slow and fast meet) // This is the same logic as Floyd's cycle detection while(slow != NULL && fast != NULL) { fast = fast->next; // Fast moves 1 step slow = slow->next; // Slow moves 1 step
if(fast != NULL) { // Ensure fast is not NULL before moving it again fast = fast->next; // Fast moves another step }
if(slow == fast) { // Pointers meet, loop detected, break break; } }
// If loop was not found (e.g., list was not guaranteed to have a loop) // This function assumes a loop exists, so this case shouldn't be hit if used correctly. if (slow == NULL || fast == NULL) { // Handle case where no loop was found (e.g., in an infinite loop due to error) return NULL; // Or throw an error, depending on design }
// STEP 2: Appoint slow to head // Reset slow pointer to the head of the list slow = head;
// STEP 3: Again Start Traversing Pointers // Move both slow and fast one step at a time. // They will meet at the beginning of the loop. while(slow != fast) { slow = slow->next; fast = fast->next; }
// STEP 4: Got the Beginning Point // Both pointers are now at the start of the loop return slow;}
// removeLoop: Removes a loop from a linked listvoid removeLoop(Node* head) { if(head == NULL) { // Empty list, nothing to remove return; }
// STEP 1: Find the beginning node of the loop Node* startOfLoop = beginningPoint(head);
// If beginningPoint returns NULL, it means there was no loop (or list was empty) if (startOfLoop == NULL) { return; }
// STEP 2: Traverse from head to the node just before the loop's beginning // Or, traverse from the loop's beginning until the node *before* it. Node* temp = startOfLoop; while(temp->next != startOfLoop) { // Move temp until it points to the node just before 'startOfLoop' temp = temp->next; }
// STEP 3: Break the loop // Set the 'next' pointer of the last node in the loop to NULL temp->next = NULL;}
// main: Program entry point, demonstrates operationsint main() { Node *head = new Node(1); // Create initial node Node *tail = head; // Tail points to head initially
// Build list: 1 -> 2 -> 4 -> 8 -> 16 -> 32 -> 64 -> 128 for(int i=1; i<=7; i++) { insertAtTail(tail, pow(2,i)); } printList(head); // Print original list
// Create a cycle for testing: 128 points to 8 (head->next->next->next) // List: 1 -> 2 -> 4 -> 8 -> 16 -> 32 -> 64 -> 128 -> (points to 8) tail->next = head->next->next->next;
// Check if a cycle is present before removal if(floydDetectLoop(head)) { cout << "Cycle is present BEFORE removal!" << endl; } else { cout << "Cycle is not present BEFORE removal!" << endl; }
// Remove the loop removeLoop(head);
// Check if a cycle is present after removal if(floydDetectLoop(head)) { cout << "Cycle is present AFTER removal!" << endl; } else { cout << "Cycle is not present AFTER removal!" << endl; }
// Print the list again to see if it's now a linear list cout << "List after removing loop: "; printList(head);
return 0; // Indicate success}
1. What is it?
- A linear data structure where elements are stored in nodes.
- Each node has:
data
(the actual value)next
(a pointer to the next node).
- The last node’s
next
pointer isNULL
. - Accessed via a
head
pointer (first node) and sometimes atail
pointer (last node for efficiency).
2. Core Node
Structure
class Node {public: int data; // The value Node* next; // Points to the next node Node(int data) { this->data = data; this->next = NULL; }};
- Key:
Node* next
is crucial for linking.
3. Basic Operations (Quick Glance)
-
printList(Node* head)
:- Purpose: Traverse and display all elements.
- How: Start at
head
, loopwhile (head != NULL)
, printhead->data
, thenhead = head->next;
. - Edge Case: If
head == NULL
, list is empty. - Example:
1->2->3
prints “Singly List : 1 2 3”
-
insertAtHead(Node* &head, int data)
:- Purpose: Add a new node at the beginning.
- How: 1. Create new node. 2. New node’s
next
points to oldhead
. 3.head
becomes new node. - Key:
head
is passed by reference (&
). - Example:
2->3
+insertAtHead(head, 1)
→1->2->3
-
insertAtTail(Node* &tail, int data)
:- Purpose: Add a new node at the end.
- How: 1. Create new node. 2. Old
tail
’snext
points to new node. 3.tail
becomes new node. - Key:
tail
is passed by reference (&
). - Example:
1->2
+insertAtTail(tail, 3)
→1->2->3
-
insertAtMiddle(Node* &head, Node* &tail, int data, int pos)
:- Purpose: Insert at a specific
pos
. - How:
- Handle
pos=1
(callinsertAtHead
). - Else, traverse (
temp
) to node beforepos
. - Insert: New node’s
next
totemp->next
,temp->next
to new node. - Update
tail
if new node is last.
- Handle
- Example:
10->20->40
+insertAtMiddle(..., 30, 3)
→10->20->30->40
- Purpose: Insert at a specific
-
deletePosition(Node* &head, int pos)
:- Purpose: Delete node at specific
pos
. - How:
- Handle
pos=1
(updatehead
,delete
old head). - Else, traverse (
temp
) to node beforepos
. - Bypass target node (
temp->next = target->next
),delete
target.
- Handle
- Example:
10->20->30
+deletePosition(head, 2)
→10->30
- Purpose: Delete node at specific
-
deleteValue(Node* &head, int val)
:- Purpose: Delete the first occurrence of
val
. - How:
- Handle
head->data == val
(updatehead
,delete
old head). - Else, use
prev
andtemp
to findval
. - Bypass
temp
(prev->next = temp->next
),delete
temp
.
- Handle
- Example:
10->20->30
+deleteValue(head, 20)
→10->30
- Purpose: Delete the first occurrence of
4. floydDetectLoop(Node* head)
Function (Prerequisite)
-
Purpose: Efficiently detect if a cycle (loop) is present in the linked list using Floyd’s Cycle-Finding Algorithm (Tortoise and Hare).
-
Concept: Uses two pointers, one moving slowly (1 step at a time) and one moving fast (2 steps at a time). If there’s a loop, the fast pointer will eventually catch up to the slow pointer. If no loop, the fast pointer will reach
NULL
. -
How it works (Step-by-Step):
- Empty List Check:
if(head == NULL)
: Returnsfalse
. An empty list cannot have a loop.
- Initialize Pointers:
Node* slow = head;
: Slow pointer starts athead
.Node* fast = head;
: Fast pointer also starts athead
.
- Traverse and Check:
while(slow != NULL && fast != NULL)
: Loop as long as both pointers are valid.fast = fast->next;
: Fast pointer moves one step.slow = slow->next;
: Slow pointer moves one step.if(fast != NULL)
: Check iffast
is still valid before moving it a second time.fast = fast->next;
: Fast pointer moves a second step.
if(slow == fast)
: If the two pointers meet at any point, a loop is detected.- Return
true
(loop detected).
- Return
- No Loop Confirmation:
- If the loop finishes (meaning
fast
orslow
becameNULL
), it indicates the fast pointer reached the end of the list without meeting the slow pointer. - Return
false
(no loop found).
- If the loop finishes (meaning
- Empty List Check:
-
Example:
Scenario 1: Non-Cyclic List
head -> 1 -> 2 -> 3 -> 4 -> NULL
Iteration slow
fast
slow == fast
?Initial 1
1
true
(initial)1 2
3
false
2 3
NULL
false
Loop Ends fast
isNULL
.- Function returns
false
. - Result: “Cycle is not present!”
Scenario 2: Cyclic List
head -> 1 -> 2 -> 3 -> 4 -> 5
^---------<--|
(5 points back to 2)Iteration slow
fast
slow == fast
?Initial 1
1
true
(initial)1 2
3
false
2 3
5
false
3 4
2
false
4 5
4
false
5 2
2
true
Loop Ends (Pointers met) - Function returns
true
. - Result: “Cycle is present!“
- Function returns
5. beginningPoint(Node* head)
Function (Prerequisite)
-
Purpose: Finds the starting node (entry point) of a loop in a linked list.
-
Pre-requisite: This function assumes that a loop already exists in the linked list (often confirmed by
floydDetectLoop
). -
Concept: Extends Floyd’s algorithm. After
slow
andfast
pointers meet (intersection point) within the loop:- Reset
slow
pointer to thehead
of the list. - Move both
slow
andfast
pointers one step at a time. They will meet again at the exact beginning of the loop.
- Reset
-
How it works (Step-by-Step):
- Phase 1: Find Intersection Node:
- Use
slow
andfast
pointers as infloydDetectLoop
to find their first meeting point within the loop.break
whenslow == fast
.
- Use
- Phase 2: Find Beginning Point:
- Reset
slow = head;
. - Loop
while(slow != fast)
:slow = slow->next;
fast = fast->next;
return slow;
(which is the loop’s start).
- Reset
- Phase 1: Find Intersection Node:
-
Example:
List with a Cycle:
head -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
^---------<--|
(6 points back to 3)-
Initial:
slow = 1
,fast = 1
-
Phase 1 (Finding Intersection):
slow
moves:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 3 -> 4 ...
fast
moves:1 -> 3 -> 5 -> 3 -> 5 -> 3 -> 5 ...
- They will eventually meet at
3
(or4
,5
,6
depending on list length and loop start, but they will meet inside the loop). Let’s assume they meet at node5
. slow
is at5
,fast
is at5
.break
.
-
Phase 2 (Finding Beginning):
slow
resets tohead
(1
).fast
remains at5
.slow
moves:1 -> 2 -> 3
fast
moves:5 -> 6 -> 3
- They both meet at node
3
.
-
Return: Node
3
.
- Result: “Beginning point of the loop : 3”
-
6. removeLoop(Node* head)
Function (New!)
-
Purpose: Removes an existing loop from a linked list, converting it back into a linear list.
-
Pre-requisite: A loop must exist in the list. This function relies on
beginningPoint
to find the loop’s start. -
Concept: After identifying the start of the loop, traverse the loop from that starting point until you reach the node just before the starting node. Set that node’s
next
pointer toNULL
. -
How it works (Step-by-Step):
- Handle Empty List:
if(head == NULL)
: Return (nothing to remove).
- Find Loop Start:
Node* startOfLoop = beginningPoint(head);
: CallbeginningPoint
to get the first node of the loop.- Important: If
beginningPoint
returnsNULL
(meaning no loop was found or list was empty),removeLoop
should also return.
- Traverse to Node Before Loop Start:
Node* temp = startOfLoop;
: Start atemp
pointer from the beginning of the loop.while(temp->next != startOfLoop)
: Movetemp
forward until itsnext
pointer points back to thestartOfLoop
. This meanstemp
is the last node in the loop.
- Break the Loop:
temp->next = NULL;
: Set thenext
pointer of the last node in the loop (temp
) toNULL
. This effectively breaks the cycle.
- Handle Empty List:
-
Example:
Initial List with Loop:
head -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
^---------<--|
(6 points back to 3)removeLoop(head)
is called.beginningPoint(head)
is called:- Phase 1:
slow
andfast
meet (e.g., at node5
). - Phase 2:
slow
resets to1
.slow
moves1 -> 2 -> 3
.fast
moves5 -> 6 -> 3
. They meet at3
. startOfLoop
is set to node3
.
- Phase 1:
temp
starts at3
.- Loop (
while(temp->next != startOfLoop)
):temp
is3
,temp->next
is4
.4 != 3
.temp
moves to4
.temp
is4
,temp->next
is5
.5 != 3
.temp
moves to5
.temp
is5
,temp->next
is6
.6 != 3
.temp
moves to6
.temp
is6
,temp->next
is3
.3 != 3
isfalse
. Loop terminates.temp
is now at node6
(the last node in the loop, which points back to the start).
temp->next = NULL;
:6->next
is set toNULL
.
Resulting List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> NULL
(The loop is successfully removed).
7. main()
Function
- Purpose: Test and demonstrate.
- Flow:
- Creates a linear list (e.g.,
1 -> 2 -> 4 -> ... -> 128
). - Prints the initial linear list.
- Manually creates a loop:
tail->next = head->next->next->next;
(e.g.,128
points to8
). - Uses
floydDetectLoop
to confirm the cycle is present. - Calls
removeLoop(head)
to break the cycle. - Uses
floydDetectLoop
again to confirm the cycle is now removed. - Prints the list again to show it’s now linear.
- Creates a linear list (e.g.,