Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Efficient Linked List Manipulation: Swapping, Removing, and Cycle Detection

Tech May 16 4

Linked lists are fundamental data structures that require careful pointer management. This article explores several advanced operations, including node swapping, element removal based on relative positioning, and detecting structural properties like intersections and cycles.

Swapping Nodes in Pairs

To swap adjacent nodes in a linked list, we use a sentinel (dummy) node to simplify edge cases, such as swappign the head node. The core logic involves maintaining a pointer to the node immediately preceding the pair being swapped.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* sentinel = new ListNode(0);
        sentinel->next = head;
        ListNode* prev = sentinel;

        while (prev->next != nullptr && prev->next->next != nullptr) {
            ListNode* first = prev->next;
            ListNode* second = prev->next->next;

            // Execute the swap
            first->next = second->next;
            second->next = first;
            prev->next = second;

            // Advance the pointer two steps
            prev = first;
        }
        
        ListNode* newHead = sentinel->next;
        delete sentinel;
        return newHead;
    }
};

When implemanting the loop condition, the order of prev->next and prev->next->next checks is critical to avoid null pointer dereferencing.

Removing the N-th Node From the End

A common strategy for locating a node relative to the end of a list is the "Two-Pointer" or "Fast-Slow Pointer" technique. By creating a specific gap between two pointers, we can identify the target node in a single pass.

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);
        ListNode* fast = dummy;
        ListNode* slow = dummy;

        // Move fast pointer so there is a gap of n nodes between fast and slow
        for (int i = 0; i <= n; i++) {
            fast = fast->next;
        }

        // Move both until fast reaches the end
        while (fast != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }

        // slow is now pointing to the node before the target
        ListNode* target = slow->next;
        slow->next = slow->next->next;
        delete target;

        ListNode* result = dummy->next;
        delete dummy;
        return result;
    }
};

Finding the Intersection of Two Linked Lists

If two linked lists intersect, they must share the same tail. By calculating the lengths of both lists, we can align their starting positions and traverse them simultaneously to find the first common node.

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lenA = 0, lenB = 0;
        ListNode *ptrA = headA, *ptrB = headB;

        while (ptrA) { lenA++; ptrA = ptrA->next; }
        while (ptrB) { lenB++; ptrB = ptrB->next; }

        ptrA = headA;
        ptrB = headB;

        // Ensure ptrA points to the longer list
        if (lenB > lenA) {
            std::swap(lenA, lenB);
            std::swap(ptrA, ptrB);
        }

        // Align the starting positions
        int diff = lenA - lenB;
        while (diff--) {
            ptrA = ptrA->next;
        }

        // Traverse together until an intersection is found
        while (ptrA != nullptr) {
            if (ptrA == ptrB) return ptrA;
            ptrA = ptrA->next;
            ptrB = ptrB->next;
        }

        return nullptr;
    }
};

Detecting the Entrance of a Cycle

Detecting a cycle is often done using Floyd's Cycle-Finding Algorithm. Once a cycle is confirmed, a mathematical relationship allows us to find the entry point: the distance from the head to the entrance is equal to the distance from the meeting point to the entrance.

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head;
        ListNode *fast = head;

        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;

            // Cycle detected
            if (slow == fast) {
                ListNode* index1 = head;
                ListNode* index2 = fast;
                
                // Find the entry point
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }
        return nullptr;
    }
};
Tags: cpp

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.