Understand pointer-based node chains, memory advantages, and master the fundamental in-place linked list reversal algorithm.
Learn how dynamic arrays achieve O(1) amortized insertion, contiguous memory layout, and geometric doubling strategies.
Unlike arrays, a Linked List stores elements in separate heap-allocated nodes where each node contains a value and a pointer (next) referencing the following node.
Array: [ 10 | 20 | 30 ] (Single contiguous block of memory addresses)
Linked List: [ 10 | * ] ──> [ 20 | * ] ──> [ 30 | null ] (Scattered memory nodes)
Node 1 Node 2 Node 3
Reversing a linked list in-place requires 3 pointers (prev, curr, next) to reorient pointers without allocating new memory:
class ListNode {
constructor(val, next = null) {
this.val = val;
this.next = next;
}
}
function reverseList(head) {
let prev = null;
let curr = head;
while (curr !== null) {
const nextTemp = curr.next; // 1. Save reference to next node
curr.next = prev; // 2. Reverse pointer backwards
prev = curr; // 3. Move prev pointer forward
curr = nextTemp; // 4. Move curr pointer forward
}
return prev; // 'prev' is now the new head of the reversed list!
}
Before: null <── [prev] [curr] ──> [nextTemp] ──> ...
│ │
Action: └─── [curr.next = prev]
| Operation | Array | Linked List |
|---|---|---|
| Insert / Delete at Head | $O(N)$ (Shifting elements) | $O(1)$ (Update head pointer) |
Index Access list[i] | $O(1)$ (Direct lookup) | $O(N)$ (Traverse from head) |
| Search by Value | $O(N)$ | $O(N)$ |
curr.next before reassigning curr.next = prev severs the rest of the list, losing all remaining nodes in memory!Use linked lists when frequent head insertions/deletions are required. Next, let's explore Stacks and the Monotonic Stack Pattern!