BST Iterator
Iterator over a BST's inorder sequence: next() and hasNext() in amortized O(1), O(h) memory.
Intuition
Pause an inorder traversal mid-flight: keep only the stack of ancestors-to-revisit (the left spine). next() pops one node and pushes the left spine of its right subtree. Each node is pushed and popped exactly once, so n calls cost O(n) total.
A paused inorder traversal. The stack holds exactly the left spine — the nodes whose values are still pending — so next() pops one and pushes the spine of its right child. Space is O(h), not O(n), because only one root-to-node path is ever stored.
Approach
Left spine = frozen traversal state
The stack holds exactly the nodes whose left sides are done but who themselves aren't emitted.
next()
Pop the top (the current smallest remaining), then walk its right child's left spine onto the stack.
hasNext()
Stack non-empty. Memory never exceeds the tree height.
Solution & live demo
Common pitfalls
Flattening the whole tree in the constructor
self.vals = inorder(root) self.i = 0
self.stack = [] self._spine(root)
Correct and often accepted, but it's O(n) memory and does all the work up front. The stack version uses O(h) and amortises the traversal across the calls that actually happen.
Pushing the right child rather than its spine
if node.right:
self.stack.append(node.right)self._spine(node.right)
The right child's own left descendants come before it in inorder. Pushing just the child returns it too early, emitting values out of order.
Descending right in the initial spine
while node:
self.stack.append(node)
node = node.rightwhile node:
self.stack.append(node)
node = node.leftInorder starts at the leftmost node. Following right pointers seeds the stack with the largest values, so the iterator returns the tree in roughly reverse order.
Edge cases
Stack holds one node at a time; each next() pushes the next chain node.
hasNext() false guards; next() on empty is undefined by contract.