Data structures · Pointers
Flip one arrow at a time
Why a linked list can add to the front for free but cannot jump to position 7 — and how three pointers turn 1 → 2 → 3 → 4 around without losing a single node.
Step the pointers yourself →01 The idea
A chain of arrows, not a block of slots
An array keeps its elements in one continuous block of memory, so element 7 sits exactly seven slots after element 0. A linked list gives that up. Each element lives in its own small box called a node, and the node stores two things: the value, and the address of the node that comes after it. The boxes can sit anywhere in memory. The only thing holding them together is that chain of addresses.
That one change decides everything else. You cannot jump to position 7, because no arithmetic finds it — you start at the head and follow seven arrows, one memory read each. But you can add a node at the front without touching a single existing node, because adding to the front means writing exactly two pointers. The array pays the opposite bill: instant indexing, but every element shifts one slot right when something joins the front.
02 Hand trace
Reversing 1 → 2 → 3 → 4 by hand
Take the list 1 → 2 → 3 → 4 → nil. Reversing it means the old tail becomes the head and every arrow turns around. The nodes themselves never move in memory — only the next field inside each one changes.
Walk it with three pointers. prev is the node behind you, curr is the node you are working on, and nxt is a scratch variable holding the node in front of you. Each row below shows what every node's next field contains after one turn of the loop, so a cell reads node→whatever its next points at. The rose cell is the arrow that just changed, and prev is always the node that curr worked on last turn.
Four nodes, four arrows, four turns of the loop, and the answer comes out of prev rather than curr — because the loop only stops once curr has walked one step past the end onto nil. Now look at turn 1 again. The moment node 1 stopped pointing at node 2, the only arrow reaching node 2 was gone. The trace survives that because nxt was written down first. Section 03 is that ordering, and nothing else.
03 The code
One line in the wrong place loses the list
Both versions below flip arrows with the same pointers and the same loop. The only difference is whether nxt is saved before or after the arrow is overwritten. The left one is what people write from memory under pressure; trace it on 1 → 2 → 3 → 4 and it hands back a one-node list.
Broken · flips before saving
reverse(head): prev = nil curr = head while curr != nil: curr.next = prev # arrow flipped first prev = curr curr = curr.next # this field is now prev return prev
Correct · saves next first
reverse(head): prev = nil curr = head while curr != nil: nxt = curr.next # save the rest first curr.next = prev # flip one arrow prev = curr # prev steps forward curr = nxt # curr steps forward return prev # prev is the new head
Why line 5 exists. nxt = curr.next is the only copy of node 2's address the program will have once the very next line runs. Nothing else in memory points at node 2. Writing it into a variable is not tidiness; it is the difference between a reversed list and three orphaned nodes.
Why the broken version stops after one turn. curr = curr.next reads a field that its own line 5 already overwrote, so it loads whatever prev was holding back at line 5 instead of the next node. On the first turn that value is nil, so curr becomes nil, the while condition fails immediately, and the function returns with one node in hand.
Why it returns prev and not curr. The loop exits when curr is nil, which is one step past the end. prev is standing on the last node it flipped — the old tail, which is exactly the new head.
05 Cheat sheet
Singly linked list against a dynamic array
| Operation | Linked list | Array | Why |
|---|---|---|---|
| Read the k-th element | O(n) | O(1) | The array computes an address; the list follows k arrows, one memory read each. |
| Insert at the head | O(1) | O(n) | The list writes two pointers; the array shifts every element one slot right. |
| Insert after a node you already hold | O(1) | O(n) | One arrow in, one arrow out. No searching, no shifting. |
| Delete a node you only have a pointer to | O(n) | O(n) | A singly linked node cannot reach the node in front of it, so you walk to find the predecessor. |
| Append at the tail, no tail pointer | O(n) | O(1) amortised | The list walks the whole chain to find the end; the array appends in place and only occasionally doubles. |
| Reverse the whole list | O(n) | O(n) | Every arrow, or every element, is touched exactly once. The list does it with O(1) extra space. |
06 Where & why
A linked list is not a faster array
It is slower at everything an array does by position, and the cheat sheet above shows it winning in only two of six rows — both of them inserts at a spot you are already standing on. It loses two rows outright and merely ties the remaining two. Its real value is narrow and specific: once you are already standing on a node, inserting or splicing there costs nothing extra, and the list never has to be copied to grow.
Reach for it when…
Use something else when…
| Situation | Better choice | Why |
|---|---|---|
| You read by index, or read far more than you write | Dynamic array — vector, ArrayList, Python list | O(1) indexing and contiguous memory, against O(n) and a likely cache miss per node. |
| You want fast pushes and pops at both ends | Deque or circular buffer — ArrayDeque, collections.deque | The same O(1) at both ends, in one block of memory, with no node allocation per push. |
| You need to find and delete an arbitrary value fast | Hash set or hash map | O(1) average lookup; the list still walks in O(n) just to locate the node. |
| You need the data kept in sorted order | Balanced BST, or a sorted array | O(log n) search. A sorted linked list still searches in O(n), because binary search needs jumps and a chain has none. |
07 Interview questions
What they actually ask
Answer in the order below and you will have covered most of a twenty-minute linked-list round. Say the numbers out loud; the complexity questions are where candidates hesitate.
What is a linked list?
Why is indexing O(n) on a list when an array does it in O(1)?
Why is inserting at the head O(1)?
Walk me through reversing a singly linked list.
What breaks if you flip the arrow before saving next?
How much extra memory does the reversal use?
Iterative or recursive reversal — which do you write?
You are handed a pointer to a node in the middle. Can you delete it in O(1)?
How do you detect a cycle in a linked list?
Singly or doubly linked — how do you choose?
When would you actually use a linked list in production?
08 Practice problems
Six problems, all pointer rewiring
Every one is solved by walking one or two pointers along the chain and rewriting next fields. Nothing here needs more than the reversal loop in section 03 and the two-pointer walk from question 9. Write them on paper first and trace each on 1 → 2 → 3 → 4 before you type anything.