Linked List Fundamentals and Algorithmic Challenges

Linked List Structure

A linked list organizes data in a linear sequence using nodes. Each node contains a data element and a pointer to the subsequent node. The initial node is called the head.

Variants of Linked Lists

Singly Linked List

Nodes contain a single pointer to the next node.

Doubly Linked List

Nodes maintain two pointers: one to the next node and another to the previous node. Enables bidirectional traversal.

Circular Linked List

The terminal node conncets back to the head node. Useful for implementing circular buffers or solving Josephus problem variations.

Memory Allocation Characteristics

Unlike arrays, linked lists allocate nodes non-contiguously in memory. Operating system memory managers handle physical distribution. Nodes reference each other through explicit pointer connections.

Node Representation

struct Node {
    int data;
    Node* next_ptr;
    Node(int value) : data(value), next_ptr(nullptr) {}
};

Initialization approaches:

// Constructor-based
Node* start_node = new Node(10);

// Manual assignment
Node* start_node = new Node();
start_node->data = 10;

Core Operations

Deletion

Modify predecessor's pointer to bypass target node. Memory reclamation required in manual management languages.

Insertion

Adjust adjacent node pointers. Constant time complexity O(1) when position is known, though search requires O(n).

Algorithmic Challenges

Value-Based Removal

Eliminate nodes matching specified value using sentinel node technique.

class Solution {
public:
    Node* eliminateValues(Node* list_head, int target) {
        Node sentinel(0);
        sentinel.next_ptr = list_head;
        Node* current = &sentinel;
        
        while (current->next_ptr) {
            if (current->next_ptr->data == target) {
                Node* obsolete = current->next_ptr;
                current->next_ptr = obsolete->next_ptr;
                delete obsolete;
            } else {
                current = current->next_ptr;
            }
        }
        return sentinel.next_ptr;
    }
};

Custom List Implementation

class LinkedListManager {
    Node dummy_head{0};
    int element_count = 0;
    
public:
    int fetchElement(int position) {
        if (position < 0 || position >= element_count) return -1;
        Node* navigator = dummy_head.next_ptr;
        for (int i = 0; i < position; ++i)
            navigator = navigator->next_ptr;
        return navigator->data;
    }
    
    void prependElement(int value) {
        Node* new_node = new Node(value);
        new_node->next_ptr = dummy_head.next_ptr;
        dummy_head.next_ptr = new_node;
        element_count++;
    }
    
    void appendElement(int value) {
        Node* new_node = new Node(value);
        Node* tail_finder = &dummy_head;
        while (tail_finder->next_ptr)
            tail_finder = tail_finder->next_ptr;
        tail_finder->next_ptr = new_node;
        element_count++;
    }
    
    void insertAtPosition(int pos, int value) {
        if (pos > element_count) return;
        if (pos < 0) pos = 0;
        
        Node* new_node = new Node(value);
        Node* locator = &dummy_head;
        for (int i = 0; i < pos; ++i)
            locator = locator->next_ptr;
        
        new_node->next_ptr = locator->next_ptr;
        locator->next_ptr = new_node;
        element_count++;
    }
    
    void removeAtPosition(int pos) {
        if (pos < 0 || pos >= element_count) return;
        
        Node* locator = &dummy_head;
        for (int i = 0; i < pos; ++i)
            locator = locator->next_ptr;
        
        Node* removed = locator->next_ptr;
        locator->next_ptr = removed->next_ptr;
        delete removed;
        element_count--;
    }
};

List Reversal

In-place iterative reversal:

Node* reverseSequence(Node* head) {
    Node* preceding = nullptr;
    Node* current = head;
    
    while (current) {
        Node* successor = current->next_ptr;
        current->next_ptr = preceding;
        preceding = current;
        current = successor;
    }
    return preceding;
}

Adjacent Pair Swapping

Node* exchangePairs(Node* head) {
    Node sentinel(0);
    sentinel.next_ptr = head;
    Node* anchor = &sentinel;
    
    while (anchor->next_ptr && anchor->next_ptr->next_ptr) {
        Node* first = anchor->next_ptr;
        Node* second = first->next_ptr;
        Node* subsequent = second->next_ptr;
        
        anchor->next_ptr = second;
        second->next_ptr = first;
        first->next_ptr = subsequent;
        
        anchor = first;
    }
    return sentinel.next_ptr;
}

Terminal Nth Node Removal

Two-pointer approach:

Node* removeNthFromEnd(Node* head, int n) {
    Node sentinel(0);
    sentinel.next_ptr = head;
    Node* lead = &sentinel;
    Node* follow = &sentinel;
    
    for (int i = 0; i <= n; ++i)
        lead = lead->next_ptr;
    
    while (lead) {
        lead = lead->next_ptr;
        follow = follow->next_ptr;
    }
    
    Node* obsolete = follow->next_ptr;
    follow->next_ptr = obsolete->next_ptr;
    delete obsolete;
    
    return sentinel.next_ptr;
}

Intersection Detection

Length-alignment strategy:

Node* findIntersection(Node* first, Node* second) {
    auto len_a = listLength(first);
    auto len_b = listLength(second);
    
    if (len_a > len_b)
        return traverseForIntersection(first, second, len_a, len_b);
    else
        return traverseForIntersection(second, first, len_b, len_a);
}

int listLength(Node* head) {
    int count = 0;
    while (head) {
        count++;
        head = head->next_ptr;
    }
    return count;
}

Node* traverseForIntersection(Node* longer, Node* shorter, int long_len, int short_len) {
    int advance = long_len - short_len;
    while (advance--) longer = longer->next_ptr;
    
    while (longer && shorter) {
        if (longer == shorter) return longer;
        longer = longer->next_ptr;
        shorter = shorter->next_ptr;
    }
    return nullptr;
}

Cycle Detection and Origin

Floyd's tortoise-hare algorithm:

Node* detectCycleOrigin(Node* head) {
    Node* slow = head;
    Node* fast = head;
    
    while (fast && fast->next_ptr) {
        slow = slow->next_ptr;
        fast = fast->next_ptr->next_ptr;
        
        if (slow == fast) {
            Node* cycle_entry = head;
            while (cycle_entry != slow) {
                cycle_entry = cycle_entry->next_ptr;
                slow = slow->next_ptr;
            }
            return cycle_entry;
        }
    }
    return nullptr;
}

Tags: Linked List Data Structures Algorithm Design Coding Interview

Posted on Wed, 19 Aug 2026 16:27:08 +0000 by opido