Home
DSA Patterns
Linked List
Reverse Linked List
Reverse Linked List
Reverse a singly linked list in place by flipping one link at a time.
Problem Understanding
Reverse a linked list: given the head of a singly linked list, reverse it and return the new head.
Example: 1 -> 2 -> 3 -> 4 -> 5 becomes 5 -> 4 -> 3 -> 2 -> 1. An empty list stays empty.
Attempt 1: Copy Into an Array
Walk the list, push every value into an array, then walk the list again writing the values back in reverse order. It works in O(n) time, but it needs O(n) extra space and it reverses the values, not the list: every node keeps its next. The in-place version reverses the links themselves with O(1) extra space.
The Intuition: Flip One Link at a Time
Reversing a list means every arrow points the other way. Walk the list once and flip one arrow per node:
curris the node whosenextyou are about to flip.previs the node it should point back at — the head of the part already reversed (NULL at the start).nextremembers the node aftercurr, because the flip is about to erase that link.
After each flip, prev and curr both step forward. When curr falls off the end, prev is sitting on the old tail — the new head.
What Goes Wrong If You Don't Save next
Suppose you flip first: curr.next = prev. That line overwrites the only pointer to the rest of the list. On 1 -> 2 -> 3, flipping node 1 first leaves 1 -> NULL, and nodes 2 and 3 are now unreachable — there is no way back to them. That is why every iteration starts with next = curr.next: save the way forward, then cut it.
Interactive Walkthrough
[1, 2, 3, 4, 5]
START
old head curr
#0
→
#1
→
#2
→
#3
→
#4
→ NULL
prev
NULL
curr
#0 (1)
next
—
prev = NULL, curr = head, node 0 (1)
Next
Save next = node 1 (2) before touching node 0 (1): the flip is about to overwrite the only link to it
Values
Legend & Complexity
curr: the node whose link is being flipped
prev: the head of the part already reversed
Reversed: its next now points back toward the old head
Done: prev is the new head
Time
O(n)
Space
O(1)
Each iteration is split into its three moves: save next, flip curr's link, then advance prev and curr. While the reversal runs, the list is drawn as two chains — the reversed part ending at NULL, and the untouched rest starting at curr — held together only by the saved next.
Dry Run Table
Input: 1 -> 2 -> 3 -> 4 -> 5 (nodes #0 to #4)
| Iteration | curr |
Save next |
Flip | Reversed so far | Then |
|---|---|---|---|---|---|
| 1 | #0 (1) |
#1 |
#0 → NULL |
1 |
prev = #0, curr = #1 |
| 2 | #1 (2) |
#2 |
#1 → #0 |
2 -> 1 |
prev = #1, curr = #2 |
| 3 | #2 (3) |
#3 |
#2 → #1 |
3 -> 2 -> 1 |
prev = #2, curr = #3 |
| 4 | #3 (4) |
#4 |
#3 → #2 |
4 -> 3 -> 2 -> 1 |
prev = #3, curr = #4 |
| 5 | #4 (5) |
NULL | #4 → #3 |
5 -> 4 -> 3 -> 2 -> 1 |
prev = #4, curr = NULL |
curr is NULL, so the loop ends and the function returns prev, node #4: 5 -> 4 -> 3 -> 2 -> 1.
The Recursive Version
The same flips can be done on the way back out of recursion. Reverse everything after head first; the node right after head is then the tail of that reversed part, so point it back at head and cut head's own link:
def reverseList(head):
if head is None or head.next is None:
return head
new_head = reverseList(head.next)
head.next.next = head
head.next = None
return new_head
On 1 -> 2 -> 3, the calls go down to node 3 (the base case, the new head). Returning, node 2's call makes 3 -> 2, then node 1's call makes 2 -> 1. Forgetting head.next = None leaves the old head pointing forward, which creates a cycle between the last two nodes. Time is O(n); space is O(n) for the call stack.
The Solution Template
Iterative in-place reversal with prev, curr and next.
Reverse Linked List Code
1var reverseList = function(head) {2 let prev = null, curr = head;3 while (curr) {4 const next = curr.next;5 curr.next = prev;6 prev = curr;7 curr = next;8 }9 return prev;10};
Edge Cases & Common Mistakes
- Empty list:
currstarts at NULL, the loop never runs, andprev(NULL) is returned. - One node: one iteration points it at NULL — already its
next— and it is returned as the new head. - Returning
headinstead ofprev: after the loop,headis the old first node, now the tail. - Flipping before saving
next: the rest of the list becomes unreachable. - Recursive version without
head.next = None: the last two nodes point at each other — a cycle.
Summary
Save next, flip curr.next to prev, advance both — once per node. The same three-pointer move appears inside harder problems: Palindrome Linked List reverses the second half, and Reorder List reverses it before weaving the halves together.
