An array stores its values side by side in one block of memory, so you can jump to any index instantly. A linked list does something different: each value lives in its own little box called a node, and every node holds a pointer to the next one. The boxes can be scattered anywhere — the pointers are what keep them in order.
That trade-off shapes everything. You give up instant indexing, but you gain cheap inserts and deletes: to splice a node in or out, you just re-point a couple of arrows.
Step through the animation on the right. First a curr pointer walks the chain by following each
next pointer. Then watch the reversal — the arrows flip backward one link at a time, and the
highlighted line of code shows exactly which step you are on.
The idea
A singly linked list is a chain of nodes. Each node knows two things: its value, and where the next node is. The very first node is the head — it is the only one you are handed, so every operation starts there. The last node's next is None, which marks the end.
To find anything, you start at the head and follow next pointers one at a time. There is no shortcut to the middle — reaching the 5th node means stepping through the first four. That is why search and access are O(n), not O(1) like an array.
Walk through it
The animation has two parts.
Traversal. A curr pointer starts at the head and follows next until it falls off the end at None. Each hop is just curr = curr.next. Visiting every node this way is O(n).
Reversal. This is the classic linked-list interview question: turn 1 -> 2 -> 3 -> 4 into 4 -> 3 -> 2 -> 1 in place (no new list). We keep three variables:
prev— the node we already reversed (starts atNone).curr— the node we are reversing now (starts at the head).nxt— a temporary save ofcurr.next, so we do not lose the rest of the list when we overwrite the pointer.
Each loop does four moves: save nxt, flip curr.next to point at prev, then slide prev and curr one step forward. Watch each arrow flip backward in the animation as its line lights up.
The code, line by line
def reverse(head):
curr = head
while curr: # traverse: follow next
curr = curr.next
prev = None # now reverse in place
curr = head
while curr:
nxt = curr.next # save next
curr.next = prev # flip the link
prev = curr # advance prev
curr = nxt # advance curr
return prev- Lines 2–4 are the traversal: follow
nextuntilcurrisNone. - Line 8 saves the rest of the list in
nxtbefore we clobber the pointer. Skip this and you lose everything aftercurrforever. - Line 9 is the actual reversal: point
currbackward atprev. - Lines 10–11 advance both pointers one step. The order matters — update
prevfirst, thencurr. - When the loop ends,
currisNoneandprevis the new head, so we returnprev.
Complexity
| Case | Time | Notes |
|---|---|---|
| Access / Search | O(n) (moderate) | must follow next from the head |
| Insert / Delete at a known node | O(1) (fast) | just re-point a couple of arrows |
| Reverse | O(n) (moderate) | one pass, flipping each link once |
O(1) (fast)The reversal touches each node exactly once, so it is O(n) time. It uses only three pointer variables no matter how long the list is, so the extra space is O(1) — it really is in place.
When to use / pitfalls
Reverse a linked list is one of the most common interview warmups. Memorize the three-pointer
pattern (prev, curr, nxt) and say out loud why you save nxt before flipping — that line is
the whole trick. Linked lists also shine when you insert and delete a lot but rarely need random
access (e.g. an LRU cache pairs a hash map with a doubly linked list).
The number-one bug: flipping curr.next before saving it. Once you do curr.next = prev, the
original next is gone, and you can never reach the rest of the list. Always save nxt = curr.next
first. The second classic bug is forgetting that prev (not curr) is the new head you return.
Practice
Halfway through reversing 1 -> 2 -> 3 -> 4, you have just flipped node 2's next to point at node 1. What are prev and curr about to become?
1. Why does accessing the 4th node of a linked list take O(n) time?
2. In the reversal loop, why do we save nxt = curr.next before doing curr.next = prev?
3. After the reversal loop finishes, what is the new head of the list?
4. What is the extra space used by the in-place reversal?