A linked list is a chain of nodes. Each node has a value and a pointer to the next node. Unlike arrays, nodes are NOT contiguous in memory.
head ↓
Access node 7 (index 1): must traverse from head → O(n). No direct jumping.
| Operation | Array | Linked List | Why |
|---|---|---|---|
| Access by index | O(1) | O(n) | LL traverses from head |
| Search | O(n) | O(n) | Both must scan |
| Insert at head | O(n) | O(1) | LL: just update pointer |
| Insert at tail | O(1)* | O(1)** | **With tail pointer |
| Insert at index | O(n) | O(n) | LL: O(n) find + O(1) link |
| Delete at head | O(n) | O(1) | LL advantage |
1. Dummy Head Node
Create a dummy node before head. Avoids special-casing when operations might affect the real head. Return dummy.next at end.
2. Fast & Slow Pointers
slow moves 1 step, fast moves 2. When fast reaches end → slow is at middle. If fast meets slow → cycle exists.
3. Reverse In-Place
prev=nullptr, cur=head. Each step: save next, point cur to prev, advance both. Classic O(n), O(1).
4. Two-Pass Technique
First pass: measure length or find a node. Second pass: process using info from first. Nth from end in O(n).
Reverse a Linked List — The Most Important Pattern
Watch the 3-pointer dance: save next, redirect cur→prev, advance both pointers. O(n) time, O(1) space.
Slow moves 1 step, fast moves 2. If there's a cycle they must meet. Watch node 6 loop back to node 3.
🧠 Under the Hood
Each node is allocated independently on the heap. The "next" field stores a raw memory address pointing to the next node — which could be anywhere in RAM. This is why linked list traversal is slow compared to arrays: every step causes a cache miss, fetching a new cache line. A sequential scan over a 1000-node list touches ~1000 different cache lines vs ~16 for an array.
⚖️ When to Use / When NOT to Use
🚫 Common Misconceptions
🎤 Interview Follow-ups
cur != nullptr before accessing cur->next. The most common linked list bug: dereferencing a null pointer.