Reversing a Linked List
Reverse a singly linked list iteratively with three-pointer rewiring and recursively, tracing each step on a whiteboard-style diagram.
Reversing a Linked List is a free DSA Interview Prep lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the DSA Interview Prep learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why List Reversal Is Essential
Reversing a linked list is among the most frequently asked coding interview questions. It tests your ability to manipulate pointers precisely without losing track of nodes. Variants appear as standalone problems and as sub-steps inside larger algorithms like palindrome detection, reorder list, and k-group reversal.
The iterative approach uses three pointers: prev, curr, and next_node. The recursive approach expresses the same logic as a call-stack traversal. Both achieve O(n) time and, for iterative, O(1) space.
Three-Pointer Iterative Reversal
At each step of the iterative reversal: save curr.next so you do not lose the rest of the list, flip curr.next to point backward to prev, advance prev to curr, and advance curr to the saved next. When curr becomes None the loop ends and prev is the new head.
A useful mnemonic: Save, Flip, Advance, Advance.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list(head):
prev, curr = None, head
while curr:
next_node = curr.next # Save
curr.next = prev # Flip
prev = curr # Advance prev
curr = next_node # Advance curr
return prev # new head
# Test
nodes = [ListNode(i) for i in range(1, 6)]
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i+1]
head = reverse_list(nodes[0])
while head:
print(head.val, end=' ') # 5 4 3 2 1
head = head.nextStep-by-Step Trace
Let us trace reverse_list on 1 -> 2 -> 3. Initially prev=None, curr=1. Step 1: save next=2, flip 1.next=None, prev=1, curr=2. Step 2: save next=3, flip 2.next=1, prev=2, curr=3. Step 3: save next=None, flip 3.next=2, prev=3, curr=None. Loop ends; return prev=3, which is the new head of 3 -> 2 -> 1.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list_traced(head):
prev, curr = None, head
step = 0
while curr:
step += 1
next_node = curr.next
curr.next = prev
print(f'Step {step}: flipped {curr.val}.next -> {prev.val if prev else None}')
prev = curr
curr = next_node
return prev
nodes = [ListNode(i) for i in [1, 2, 3]]
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i+1]
head = reverse_list_traced(nodes[0])
print('New head:', head.val) # 3Recursive Reversal
The recursive approach trusts that reverse_list(head.next) returns the new head of the already-reversed suffix. All that remains is to flip the pointer between head and head.next: set head.next.next = head (point the old second node back to the old first) and head.next = None (sever the old forward link). The new head bubbles up from the base case.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list_rec(head):
# Base case: empty or single node
if not head or not head.next:
return head
new_head = reverse_list_rec(head.next) # reverse suffix
head.next.next = head # former second node points back
head.next = None # sever forward link
return new_head
nodes = [ListNode(i) for i in range(1, 5)]
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i+1]
head = reverse_list_rec(nodes[0])
while head:
print(head.val, end=' ') # 4 3 2 1
head = head.nextReversing a Sub-List (LeetCode 92)
LeetCode 92 'Reverse Linked List II' asks you to reverse the sub-list from position left to right (1-indexed) in one pass. The trick is to locate the node before the sub-list (use a dummy head so this is always valid), then perform the three-pointer reversal for exactly (right - left) steps, and finally reconnect the reversed segment to the surrounding list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverseBetween(head, left, right):
dummy = ListNode(0, head)
pre = dummy
# Advance pre to node just before position 'left'
for _ in range(left - 1):
pre = pre.next
curr = pre.next
for _ in range(right - left):
next_node = curr.next
curr.next = next_node.next
next_node.next = pre.next
pre.next = next_node
return dummy.next
nodes = [ListNode(i) for i in range(1, 6)]
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i+1]
head = reverseBetween(nodes[0], 2, 4)
while head:
print(head.val, end=' ') # 1 4 3 2 5
head = head.nextReverse Nodes in K-Group (LeetCode 25)
LeetCode 25 'Reverse Nodes in k-Group' reverses every consecutive group of k nodes. The approach: check if k nodes remain; if not, leave them as-is. Reverse the next k nodes using the iterative method, then recursively reverse the remaining list and connect it. The time complexity remains O(n) with O(n/k) recursive call depth.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverseKGroup(head, k):
# Check if k nodes are available
curr, count = head, 0
while curr and count < k:
curr = curr.next
count += 1
if count < k:
return head # fewer than k nodes left, keep as-is
# Reverse k nodes
prev, curr = None, head
for _ in range(k):
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
# head is now the tail of the reversed group
head.next = reverseKGroup(curr, k)
return prev
nodes = [ListNode(i) for i in range(1, 6)]
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i+1]
head = reverseKGroup(nodes[0], 2)
while head:
print(head.val, end=' ') # 2 1 4 3 5
head = head.nextPalindrome Linked List
LeetCode 234 'Palindrome Linked List': check if a linked list is a palindrome in O(n) time, O(1) space. Strategy: find the midpoint with slow-fast pointers, reverse the second half in place, compare the two halves node by node, then optionally restore the list. This chains together midpoint finding and reversal — two foundational skills.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def isPalindrome(head):
# Find mid
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# Reverse second half
prev, curr = None, slow
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
# Compare
left, right = head, prev
while right:
if left.val != right.val:
return False
left = left.next
right = right.next
return True
def build(arr):
d = ListNode(0)
c = d
for v in arr:
c.next = ListNode(v)
c = c.next
return d.next
print(isPalindrome(build([1,2,2,1]))) # True
print(isPalindrome(build([1,2,3]))) # FalseIterative vs Recursive Comparison
The iterative reversal uses O(1) space and is generally preferred. The recursive reversal uses O(n) stack space due to call depth, which can cause a stack overflow for very long lists (Python's default limit is ~1000 recursion levels).
In an interview, implement the iterative version first to show awareness of space constraints, then mention the recursive version as a cleaner alternative if the list length is bounded.
import sys
print('Default recursion limit:', sys.getrecursionlimit())
# For a list of 10,000 nodes the recursive reversal would hit this limit
# Iterative reversal has no such constraint
# Increase if needed (use sparingly):
# sys.setrecursionlimit(20000)Common Mistakes in Reversal
Three mistakes account for almost all reversal bugs. First, not saving next before overwriting: curr.next = prev destroys the forward reference if next_node was not saved. Second, not returning prev: at the end of the loop, curr is None but prev is the new head. Third, wrong recursive base case: forgetting not head.next means a single-node list is not handled and causes an AttributeError.
# Minimal correct iterative reversal — annotated against common bugs
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_list(head):
prev, curr = None, head
while curr:
next_node = curr.next # BUG if omitted: lose rest of list
curr.next = prev
prev = curr
curr = next_node
return prev # BUG if you return curr: it is None
nodes = [ListNode(i) for i in [1, 2, 3]]
nodes[0].next = nodes[1]
nodes[1].next = nodes[2]
h = reverse_list(nodes[0])
while h:
print(h.val, end=' ') # 3 2 1
h = h.nextReorder List (LeetCode 143)
LeetCode 143 'Reorder List' rearranges L0 → L1 → L2 → ... → Ln into L0 → Ln → L1 → Ln-1 → L2 → Ln-2 in O(n) time, O(1) space. The solution combines three steps: find the midpoint, reverse the second half, and interleave the two halves. Mastering reversal makes this seemingly complex problem a straightforward combination of familiar tools.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reorderList(head):
if not head or not head.next:
return
# Find mid
slow = fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
# Reverse second half
prev, curr = None, slow.next
slow.next = None
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
# Interleave
first, second = head, prev
while second:
tmp1, tmp2 = first.next, second.next
first.next = second
second.next = tmp1
first, second = tmp1, tmp2
nodes = [ListNode(i) for i in range(1, 5)]
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i+1]
reorderList(nodes[0])
h = nodes[0]
while h:
print(h.val, end=' ') # 1 4 2 3
h = h.nextSummary: Reversal Is a Building Block
Linked list reversal is rarely the final goal — it is a building block. Palindrome detection, k-group reversal, reorder list, and reverse between positions all rely on the same three-pointer iterative pattern. Once the pattern is automatic you can focus mental bandwidth on the higher-level problem structure.
Always practise reversal until you can write it from memory in under two minutes; it will appear in some form in nearly every linked-list interview round.
Quick Check
Test your understanding of Data Structures & Algorithms — Coding Interview Prep concepts from this lesson.
Lesson Recap
In this lesson you learned: the iterative Save-Flip-Advance-Advance pattern reverses a list in O(n) time and O(1) space, the recursive approach trusts the suffix is already reversed and only fixes the last link, and reversal is a core sub-step in palindrome detection, reorder list, and k-group reversal. Next up we explore cycle detection with Floyd's algorithm.
Frequently asked questions
Is the “Reversing a Linked List” lesson free?
Yes — the full text of “Reversing a Linked List” is free to read here on the web, and the DSA Interview Prep course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the DSA Interview Prep course, upgrade to CoddyKit PRO.
What will I learn in “Reversing a Linked List”?
Reverse a singly linked list iteratively with three-pointer rewiring and recursively, tracing each step on a whiteboard-style diagram. You practise DSA Interview Prep with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start DSA Interview Prep?
No prior experience is required. DSA Interview Prep on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Reversing a Linked List” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this DSA Interview Prep lesson?
Yes. Every DSA Interview Prep lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.