Linked Lists & Pointer Nodes
Master non-contiguous heap allocation, node pointer management, sentinel dummy heads, O(1) in-place list reversals, and Floyd's Tortoise and Hare cycle finding.
Node Architecture & Heap Pointers
A linked list is a recursive, dynamic data structure where each node stores Data and one or more Pointers (References) to adjacent nodes in heap memory. Unlike arrays, nodes are not stored contiguously, allowing instant O(1) insertions and deletions once the target pointer is known.
- Singly Linked List:Each node has
valandnext. Traversal is strictly forward. - Doubly Linked List:Each node has
val,next, andprev, enabling bidirectional traversal and true O(1) node removals (used in LRU Cache). - Dummy (Sentinel) Node Pattern:Placing a dummy node before
head(dummy.next = head) eliminates edge case checks when deleting or modifying the head node.
- In-Place 3-Pointer Reversal: Maintain
prev = None,curr = head, andnext_temp = None. In each iteration:next_temp = curr.next; curr.next = prev; prev = curr; curr = next_temp. - Floyd's Cycle Detection (Tortoise and Hare): Initialize
slow = headandfast = head. Advanceslowby 1 step andfastby 2 steps. If a cycle exists, they must meet at a node inside the loop. - Finding the Cycle Entry Point: When
slowandfastmeet, resetslow = headwhile keepingfastat the collision point. Advance both by 1 step simultaneously; the node where they meet is the exact cycle entry.
A pointer algorithm that uses two pointers moving at different speeds (1x and 2x) to detect loops in linear data structures in O(N) time and O(1) space.
Cycle Entry Mathematical Proof
Singly vs Doubly Linked List Benchmark
| Property | Singly Linked List | Doubly Linked List | Dynamic Array (Vector) |
|---|---|---|---|
| Node Memory Overhead | 1 Pointer (8 bytes) | 2 Pointers (16 bytes) | Zero Overhead |
| Prepend (Head Insert) | O(1) | O(1) | O(N) Shift |
| Append (with Tail) | O(1) | O(1) | O(1) Amortized |
| Delete Known Node | O(N) (needs prev) | O(1) (has prev)Optimal | O(N) Shift |
Whenever a problem asks you to remove, reorder, or partition linked list nodes, ALWAYS create a dummy sentinel node `dummy = ListNode(0, head)`. It prevents edge case bugs when mutating the first element.
1class ListNode:2 def __init__(self, val=0, next=None):3 self.val = val4 self.next = next56def reverse_list(head: ListNode) -> ListNode:7 prev = None8 curr = head9 while curr:10 next_temp = curr.next11 curr.next = prev12 prev = curr13 curr = next_temp14 return prev1516# Helper to build and print list17def print_list(node):18 vals = []19 while node:20 vals.append(str(node.val))21 node = node.next22 return ' -> '.join(vals) + ' -> None'2324head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))25print('Original List:', print_list(head))26reversed_head = reverse_list(head)27print('Reversed List:', print_list(reversed_head))
Original List: 1 -> 2 -> 3 -> 4 -> 5 -> None Reversed List: 5 -> 4 -> 3 -> 2 -> 1 -> None
1struct ListNode {2 int val;3 ListNode *next;4 ListNode(int x) : val(x), next(nullptr) {}5};67ListNode *detectCycle(ListNode *head) {8 if (!head || !head->next) return nullptr;9 ListNode *slow = head, *fast = head;10 while (fast && fast->next) {11 slow = slow->next;12 fast = fast->next->next;13 if (slow == fast) {14 ListNode *entry = head;15 while (entry != slow) {16 entry = entry->next;17 slow = slow->next;18 }19 return entry;20 }21 }22 return nullptr;23}
[Returns pointer to cycle entry node or nullptr]
Quick Syntax & Reference Sheet
| Concept / Rule | Syntax / Usage |
|---|---|
| Dummy Head | dummy = ListNode(0, head); curr = dummy |
| Reverse List | prev = None; while curr: nxt = curr.next; curr.next = prev; prev = curr; curr = nxt |
| Cycle Check | slow = head, fast = head; while fast and fast.next: slow = slow.next, fast = fast.next.next |
Common Pitfalls & Developer Mistakes
Losing reference to the next node before modifying curr.next
Why it happens: Assigning `curr.next = prev` before saving `curr.next` causes the rest of the list to be lost forever in memory.
# Correct:
next_temp = curr.next
curr.next = prev
prev = curr
curr = next_temp