Data StructuresBeginner

Reverse Linked List in Python

Learn how to reverse a linked list in Python! An easy, fun, beginner-friendly guide to solving this classic coding interview algorithm. Includes O(1) space iterative code.

Try it yourself

Run this code directly in your browser. Click "Open in full editor" to experiment further.

Loading...

Click Run to see output

Or press Ctrl + Enter

How it works

Reverse linked list python — if one algorithm question has launched a thousand whiteboard interviews, this is it. Leetcode 206: take 1 → 2 → 3 → 4 → 5 and return 5 → 4 → 3 → 2 → 1. Five lines, zero hand-waving. It's the canonical pointer manipulation python drill — a tiny problem that ruthlessly exposes whether you understand references, mutation, and order of operations. 🧠

If you can explain linked list reversal out loud while writing it, you can handle the rest of the trees-and-graphs gauntlet.

What's a Linked List?

A linked list is a chain of nodes, where each node holds a value and a next pointer to the node after it. The last node's next is None.

  • Singly linked: each node knows only the next one. One-way. ➡️
  • Doubly linked: each node has next and prev. Two-way. ↔️
  • A Python list ([1, 2, 3]) is not a linked list. It's a dynamic array — contiguous memory with O(1) random access. A real linked list has O(n) access but O(1) insertion if you already hold a pointer. Different beasts.

    class ListNode:
        def __init__(self, val=0, next=None):
            self.val = val
            self.next = next

    The Iterative Approach

    The iterative solution uses three pointers: prev, curr, and a temporary next_temp. Three steps repeat until curr walks off the end:

    1. Save the next node so we don't lose the rest of the list.

    2. Rewire curr.next to point backwards at prev.

    3. Advance prev and curr one step forward.

    Reverse 1 → 2 → 3 → 4. Initial: prev = None, curr = 1.

    Iterationprevcurrnext_tempAfter rewire
    StartNone11 → 2 → 3 → 4
    1122None ← 1, 2 → 3 → 4
    2233None ← 1 ← 2, 3 → 4
    3344None ← 1 ← 2 ← 3, 4
    44NoneNoneNone ← 1 ← 2 ← 3 ← 4

    When curr is None, prev sits on the new head. Return prev. That's it.

    The Recursive Approach

    The recursive version is gorgeous but bends your brain the first time. Three beats:

    1. Base case: if the list is empty or one node, it's already reversed. Return it.

    2. Recurse first: hand head.next to the function; trust it returns a reversed sublist whose tail is your immediate neighbour.

    3. Rewire on the way back up: your neighbour (head.next) points at None. Tell it to point at you (head.next.next = head), then break your own forward link (head.next = None) so you don't form a cycle.

    def reverse(head):
        if not head or not head.next:
            return head
        new_head = reverse(head.next)
        head.next.next = head
        head.next = None
        return new_head

    The head.next.next = head line is the one people stare at. Read it as: "the node in front of me — point its next back at me." Once that clicks, the rest collapses into common sense.

    Complexity Analysis

    ApproachTimeSpaceNotes
    IterativeO(n)O(1)Three pointers, one pass. Interview-preferred.
    RecursiveO(n)O(n)Elegant, but the call stack costs n frames. Risk of RecursionError.

    Both touch every node once. The space gap is the whole story — and it's why senior engineers reach for the iterative version first.

    Common Pitfalls

  • Losing the next pointer. Writing curr.next = prev before saving next_temp = curr.next makes the rest of the list vanish. Save first, then mutate. ⚠️
  • Returning `curr` instead of `prev`. When the loop exits, curr is None. The new head is prev. Return the wrong one and you hand back an empty list.
  • Off-by-one on the recursive base case. You need both checks: if not head or not head.next. Either alone misses a case.
  • Confusing the initial `prev = None`. That None becomes the new tail's next, terminating the reversed list. Initialising prev = head is a classic bug.
  • Forgetting `head.next = None` in recursion. Skip it and node 1 points at 2 and 2 points at 1 — you've built a cycle.
  • Mutating the original unintentionally. Both approaches reverse in-place, so head now points at the tail. Deep-copy first if you need the original intact.
  • Why Interviewers Love This

    Five lines, infinite signal. It tests your pointer mental model, forces edge-case thinking (empty list, single node), makes you choose iterative vs recursive, and rewards candidates who mention O(1) space. Nowhere to hide. 🎯

    Variants You Will See

  • Reverse Linked List II (LeetCode 92) — reverse only between positions left and right.
  • Reverse Nodes in k-Group (LeetCode 25) — reverse every k nodes; the hard-mode cousin.
  • Palindrome Linked List (LeetCode 234) — reverse the second half and compare with the first.
  • Swap Nodes in Pairs (LeetCode 24) — a degenerate k=2 reversal.
  • Real-World Uses

  • Undo stacks in editors — walking history backwards.
  • Browser history back-button on a navigation chain.
  • Reversing transaction logs to replay events newest-first.
  • Building a stack from a queue in low-level systems.
  • Parsing reversed token streams in some compilers.
  • Time-series processing newest → oldest without copying.
  • Why Python Devs Rarely Implement This in Real Code

    In production Python you almost never write a linked list. The built-in list is a dynamic array with O(1) append and random access — perfect for 95% of cases. For queue/stack workloads, collections.deque gives O(1) at both ends. Linked lists shine only when you need $O(1)$ insertion at an arbitrary position you already hold a pointer to (intrusive lists in kernels, some graph algorithms) or low-level systems work in C/Rust. The algorithm still matters for interviews and for understanding why deque is fast. 🐍

    Frequently Asked Questions

    Why does Python not have a built-in linked list? Because list and collections.deque cover almost every practical case with better cache locality.

    Iterative or recursive — which is better? Iterative. It's O(1) space, won't blow the stack on long lists, and is easier to reason about under pressure.

    Can I reverse without modifying the original? Yes — walk the list, copy each node into a new chain, reverse as you build. Costs O(n) extra space but leaves the input untouched.

    Singly vs doubly linked list reversal? For a doubly linked list you swap each node's next and prev pointers in one pass — still O(n) time, O(1) space, but symmetric.

    How do I reverse only part of a list? That's LeetCode 92. Walk to left-1, reverse the segment with the same three-pointer dance, then reattach both ends.

    Why is recursive $O(n)$ space? Each call adds a stack frame. For a list of length n, n frames stay pending until the base case fires — so the call stack grows linearly, even though no new nodes are allocated.

    Related examples