In-order iterator for binary tree
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
An in-order iterator lets you traverse a binary tree one element at a time without writing recursive traversal code at every call site. The usual iterative solution stores the path to the next node in a stack, giving you ordered traversal with predictable space usage.
How in-order traversal works
In-order traversal visits nodes in this sequence:
- left subtree
- current node
- right subtree
For a binary search tree, that produces values in sorted order. The challenge for an iterator is preserving just enough state to resume where the previous next() call stopped.
A stack-based iterator
The standard pattern is:
- push the entire left chain from the current root,
- pop the top node when
next()is called, - then push the left chain of that node's right child.
Here is a complete Python implementation:
The helper method _push_left is the key. It keeps the next smallest unvisited node on top of the stack.
Example usage
Build a small tree:
Output:
That ordering comes from always exhausting the left side before visiting a node and then moving to its right subtree.
Why the complexity is efficient
Each node is pushed onto the stack once and popped once, so the total work is linear in the number of nodes. A single next() call is amortized O(1), while the stack uses O(h) space where h is the tree height.
That is a good tradeoff because the iterator does not need to store all node values in advance. It yields them lazily as requested.
Returning nodes instead of values
Sometimes the caller needs the whole node instead of just the value. In that case, return node from __next__ instead of node.value. The traversal algorithm does not change.
You can also add a has_next() helper in languages that prefer it:
Python's iterator protocol does not require that method, but Java and C++ style iterators often expose an equivalent check.
Common Pitfalls
The most common bug is forgetting to push the left chain of the popped node's right child. If you skip that step, the iterator visits the root of the right subtree but misses everything below its left branch.
Another issue is assuming next() is worst-case constant time. A single call may walk down several left children, but across the entire traversal each node is still processed only once, which is why the amortized cost stays low.
Be careful when modifying the tree during iteration. If nodes are inserted or removed while the iterator is active, the stack may no longer represent a consistent traversal state.
Finally, do not replace the stack with recursion if the goal is a reusable iterator. Recursion is fine for one-off traversal, but an iterator needs explicit state between calls.
Summary
- An in-order iterator uses a stack to remember the path to the next node.
- The core rule is: pop one node, then push the left chain of its right child.
- The iterator yields sorted values for a binary search tree.
- Space usage is
O(h)and total traversal time isO(n). - Explicit iterator state is what makes lazy, step-by-step traversal possible.

