Merge Two Sorted Lists is the linked-list version of the merge step inside merge sort. It is a gentle introduction to two ideas you will reuse constantly: walking two pointers in lockstep, and using a dummy head to dodge annoying edge cases.
Problem. You are given the heads of two already sorted linked lists, a and b. Splice their
nodes together into one sorted list and return its head. The new list reuses the existing nodes.
Example: a = [1, 2, 4], b = [1, 3, 4] → [1, 1, 2, 4, 4].
The idea
Both lists are already sorted, so the smallest unused value is always at one of the two heads. Look at both heads, take the smaller one, and move that list's pointer forward. Repeat. When one list runs out, the other list is already sorted, so just attach all of it at once.
The one nuisance is the very first node: it has no "previous" node to link from. The classic trick is a dummy head — a throwaway node we always have in hand. We attach merged nodes after the dummy, and at the end the real answer is dummy.next. This removes every "is this the first node?" special case.
A tail pointer remembers the end of the merged list so each new node is an O(1) append. Ties (equal heads) can go to either list; taking from a keeps the merge stable.
Walk through it
Step through the animation. Pointers a and b sit on the heads of the two rows. At each compare, the smaller head drops into the tail row and its pointer slides forward. When a empties after appending 4, the loop stops and the leftover 4 in b is attached in one move.
Pseudocode
make a dummy node; let tail = dummy
while both a and b are non-empty:
if a.val <= b.val:
tail.next = a; advance a
else:
tail.next = b; advance b
advance tail to the node we just attached
tail.next = whichever list is left (a or b) # the other is empty
return dummy.next # skip the dummyThe loop runs while both lists have nodes. The moment one empties, the remaining list is appended wholesale.
The Python solution
def merge(a, b):
dummy = ListNode()
tail = dummy
while a and b:
if a.val <= b.val:
tail.next = a
a = a.next
else:
tail.next = b
b = b.next
tail = tail.next
tail.next = a or b
return dummy.nextdummyis a placeholder node so the first append needs no special case;tailalways points at the last node of the merged list.- The
while a and bloop keeps going only while both lists still have a node to compare. a.val <= b.valpicks the smaller head.<=(not<) sends ties toa, which makes the merge stable.- After attaching a node we slide that list's pointer (
a = a.nextorb = b.next) and thentail = tail.next. tail.next = a or battaches the non-empty leftover list in one shot (a or bis whichever is notNone).- We return
dummy.next— the real head, skipping the placeholder.
Complexity
| Case | Time | Notes |
|---|---|---|
| Merge both lists | O(n + m) (moderate) | each node is visited once |
O(1) (fast)We touch every node exactly once, so time is O(n + m) where n and m are the two lengths. We only rewire existing nodes — no new list is allocated — so extra space is O(1) (the dummy is a single node).
When this pattern shows up
The dummy-head trick appears all over linked-list problems: merging, removing nodes, partitioning,
reversing in groups. Any time the head of the result might change or the first node is awkward to handle,
start with a dummy node and return dummy.next. It deletes a whole class of edge cases.
Don't forget the leftover tail. When the loop exits, one list still has nodes — tail.next = a or b
attaches them. Skipping this line silently drops the rest of the longer list.
Practice
Merging a = [1, 2, 4] and b = [1, 3, 4], after both 1s and the 2 are placed, the heads are a = 4 and b = 3. Which node is attached next, and which pointer moves?
1. What is the point of the dummy head node?
2. When the while loop exits, what does tail.next = a or b do?
3. Why use a.val <= b.val instead of a.val < b.val for ties?
4. What is the time complexity of merging lists of length n and m?