0
0
DSA Typescriptprogramming

BST Iterator Design in DSA Typescript

Choose your learning style9 modes available
Mental Model
A BST iterator lets you see the tree's values one by one in order, like reading a book page by page without holding the whole book open.
Analogy: Imagine a bookmark that remembers where you stopped reading in a sorted book, so you can pick up exactly where you left off without rereading pages.
      7
     / \
    3   15
       /  \
      9    20

Stack: []
Iterator at start, ready to go leftmost.
Dry Run Walkthrough
Input: BST with nodes 7, 3, 15, 9, 20; iterate through all values in ascending order
Goal: Return values one by one in sorted order using next() and hasNext() methods
Step 1: Initialize iterator by pushing leftmost nodes onto stack
Stack: [7, 3]
Current node not yet returned
Why: We start at the smallest value by going left as far as possible
Step 2: Call next(), pop 3 from stack and return it
Stack: [7]
Returned value: 3
Why: 3 is the smallest node, so we return it first
Step 3: Call next(), pop 7 from stack and return it; push leftmost nodes of 7's right child (15)
Stack: [15, 9]
Returned value: 7
Why: After 7, we explore its right subtree starting at 15
Step 4: Call next(), pop 9 from stack and return it
Stack: [15]
Returned value: 9
Why: 9 is next smallest after 7
Step 5: Call next(), pop 15 from stack and return it; push leftmost nodes of 15's right child (20)
Stack: [20]
Returned value: 15
Why: After 15, move to its right child 20
Step 6: Call next(), pop 20 from stack and return it
Stack: []
Returned value: 20
Why: 20 is the largest node, iteration ends after this
Step 7: Call hasNext(), return false since stack is empty
Stack: []
No more nodes to return
Why: No nodes left means iteration is complete
Result:
Stack: []
Returned values in order: 3 -> 7 -> 9 -> 15 -> 20
Iteration complete
Annotated Code
DSA Typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = val === undefined ? 0 : val;
    this.left = left === undefined ? null : left;
    this.right = right === undefined ? null : right;
  }
}

class BSTIterator {
  private stack: TreeNode[] = [];

  constructor(root: TreeNode | null) {
    this.pushLeft(root);
  }

  private pushLeft(node: TreeNode | null): void {
    while (node !== null) {
      this.stack.push(node); // push current node to stack
      node = node.left; // move to left child
    }
  }

  next(): number {
    const node = this.stack.pop()!; // pop top node
    if (node.right !== null) {
      this.pushLeft(node.right); // push left path of right subtree
    }
    return node.val; // return current node's value
  }

  hasNext(): boolean {
    return this.stack.length > 0; // check if any nodes left
  }
}

// Driver code to test iterator
const root = new TreeNode(7,
  new TreeNode(3),
  new TreeNode(15, new TreeNode(9), new TreeNode(20))
);
const iterator = new BSTIterator(root);
const result: number[] = [];
while (iterator.hasNext()) {
  result.push(iterator.next());
}
console.log(result.join(' -> ') + ' -> null');
while (node !== null) { this.stack.push(node); // push current node to stack node = node.left; // move to left child }
push all left children to stack to reach smallest node
const node = this.stack.pop()!; // pop top node
pop the next smallest node to return
if (node.right !== null) { this.pushLeft(node.right); // push left path of right subtree }
after returning a node, prepare stack with left path of its right subtree
return node.val; // return current node's value
return the value of the current node
return this.stack.length > 0; // check if any nodes left
check if iteration can continue
OutputSuccess
3 -> 7 -> 9 -> 15 -> 20 -> null
Complexity Analysis
Time: O(1) amortized per next() call because each node is pushed and popped once
Space: O(h) where h is tree height, due to stack storing left path nodes
vs Alternative: Compared to inorder traversal storing all nodes (O(n) space), this uses less memory by storing only path nodes
Edge Cases
Empty tree (root is null)
Iterator stack remains empty, hasNext() returns false immediately
DSA Typescript
while (node !== null) { this.stack.push(node); node = node.left; }
Tree with single node
Stack contains one node, next() returns that node's value, then hasNext() returns false
DSA Typescript
const node = this.stack.pop()!;
Tree with only left children
Stack initially contains all nodes, next() returns nodes in ascending order without pushing right children
DSA Typescript
while (node !== null) { this.stack.push(node); node = node.left; }
When to Use This Pattern
When asked to iterate over a BST in sorted order with next() and hasNext(), use a controlled stack to simulate inorder traversal lazily.
Common Mistakes
Mistake: Pushing all nodes of the tree onto stack at once, using O(n) space
Fix: Only push leftmost path nodes and push right subtree's left path when needed
Mistake: Not pushing left children of right subtree after popping a node
Fix: After popping a node, call pushLeft on its right child to maintain correct order
Summary
Provides an iterator to traverse BST nodes in ascending order using controlled stack.
Use when you want to access BST elements one by one without storing all nodes.
The key is to push leftmost nodes and update stack with right subtree's left path after each next().