In Plain English

New to this one? Start here. Below is the core idea in everyday language, plus a real-world analogy—then the sections that follow build on it with the formal reasoning, code, and step-by-step walkthroughs.

🌱 Real-world analogy: reading a book with footnotes

You read a line and hit a footnote marker. Before continuing the sentence, you jump down to read the entire footnote (which may contain its own footnotes). When it's finished, you return and pick up exactly where you left off. Flattening turns that nested reading order into one long, linear transcript — children first, then the rest of the line.

Dry Runs

Two step-by-step walkthroughs of the algorithm below: a valid case (the expected happy path) and an invalid / edge case that exercises the tricky parts. Each step shows the program state as the code runs—the same steps apply to Python, C++ and Java.

✅ Dry run 1 (one level) — 1 → 2 → 3 with 2.child = 7 → 8 flattens to 1, 2, 7, 8, 3.

has a child appended to the flat list

Input. Node 2 has a child branch hanging below it.
1
2
3
7
8
Pop 1. Link after dummy. Push next=2. Stack top: [2].
1
Pop 2. Link after 1. Push next=3, then push child=7 (goes on top); clear 2.child. Stack: [3, 7].
1
2
Pop 7, then 8. The child branch is threaded in. Push 8 (7's next); 8 has no next/child. Stack: [3].
1
2
7
8
Pop 3. The saved successor of 2 comes last. Flatten complete. 🎉
1
2
7
8
3
null

The same run as a table

Stack shown top-of-stack on the right. Each pop appends one node to the flat list.
poppush nextpush childstack afterflat list so far
12[2]1
237[3, 7]1, 2
78[3, 8]1, 2, 7
8[3]1, 2, 7, 8
3[]1, 2, 7, 8, 3
📈 Dry run 2 (nested) — 2.child = 7 → 8 and 7.child = 9 flattens to 1, 2, 7, 9, 8, 3.

has a child appended to the flat list

Input. Node 2 has a child 7 → 8, and node 7 itself has a child 9 — two levels deep.
1
2
3
7
8
9
Pop 1. Link after dummy. Push next=2. Stack: [2].
1
Pop 2. Link after 1. Push next=3, then push child=7 (on top); clear 2.child. Stack: [3, 7].
1
2
Pop 7. Link after 2. Push next=8, then push child=9 (on top); clear 7.child. Stack: [3, 8, 9].
1
2
7
Pop 9. The deepest child is threaded in first, right after 7. No next/child. Stack: [3, 8].
1
2
7
9
Pop 8. 7's original next comes after the child branch. No next/child. Stack: [3].
1
2
7
9
8
Pop 3. 2's saved successor comes last. Stack empty → flatten complete. 🎉
1
2
7
9
8
3
null

The same run as a table

Stack shown top-of-stack on the right. Pushing child after next keeps the deepest branch on top, so it is threaded in first.
poppush nextpush childstack afterflat list so far
12[2]1
237[3, 7]1, 2
789[3, 8, 9]1, 2, 7
9[3, 8]1, 2, 7, 9
8[3]1, 2, 7, 9, 8
3[]1, 2, 7, 9, 8, 3

Contrast with Dry run 1: node 7 itself has a child (9). Because a node's child is pushed on top of its next, the deeper branch is always threaded in first — so 9 lands right after 7, before 8. One stack handles any depth; only its height grows.

The same steps in each language

Both runs step exactly as the tables above. Python pushes curr.next first then curr.child (child ends up on top), and sets curr.child = None after pushing.

Same steps. C++: st.push(curr->next) then st.push(curr->child); set curr->child = nullptr.

Same steps. Java: stack.push(curr.next) then stack.push(curr.child); set curr.child = null.