Intermediate 4 min · March 05, 2026

BST to Sorted Array — Degenerate Tree Stack Overflow Fix

Sorted input creates O(n) height BSTs causing StackOverflowError at 10K nodes.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • In-order traversal visits nodes as left → root → right, yielding ascending order.
  • Convert BST to sorted array: traverse in-order and collect values into a list.
  • Convert sorted array to BST: pick middle element as root, recurse on left and right halves.
  • Recursive conversion: O(n) time, O(h) stack space — risk of StackOverflow on degenerate trees.
  • Iterative conversion: O(n) time, O(h) explicit stack — production-safe for any tree shape.
  • Biggest mistake: building BST from sorted input without rebalancing, causing degenerate tree and deep recursion.
Plain-English First

Imagine a library where books are shelved in a special way: every book on the left shelf is alphabetically earlier than the current book, and every book on the right shelf comes after it. If you walk through that library always going left first, then reading the current book, then going right — you'll read every book in perfect alphabetical order without any sorting effort. A Binary Search Tree (BST) is that library, and in-order traversal is that exact walking pattern. Converting a BST to a sorted array is just writing down the titles as you walk.

Sorted data is the foundation of fast searching, clean output, and reliable comparisons. But in the real world, data rarely arrives pre-sorted in an array — it's often stored in a BST because insertion and lookup are O(log n). When you need to export that data, merge it with another dataset, or display it to a user, you need a flat, sorted list. Knowing how to flatten a BST into a sorted array efficiently is a skill that shows up everywhere from database query engines to autocomplete systems.

The problem this solves is deceptively simple to state but easy to get wrong: given the root of a BST, produce an array where every element is in ascending order. The naive approach — dump all nodes into an array and call Arrays.sort() — works but wastes the BST's built-in ordering guarantee entirely. The smart approach exploits the BST property directly, giving you a sorted array in O(n) time with zero comparisons.

By the end of this article you'll understand exactly why in-order traversal produces sorted output (not just that it does), you'll have two complete runnable implementations (recursive and iterative), you'll know the three most common mistakes developers make, and you'll be ready to field the interview questions that trip people up most.

What is Convert BST to Sorted Array? — Plain English

A Binary Search Tree (BST) has a fundamental property: for any node, all values in its left subtree are smaller, and all values in its right subtree are larger. In-order traversal (left → root → right) of a BST visits nodes in ascending sorted order. This means converting a BST to a sorted array is as simple as performing an in-order traversal and collecting node values. The reverse direction — converting a sorted array to a height-balanced BST — works by always picking the middle element of the current subarray as the root, then recursively building the left subtree from the left half and right subtree from the right half. This ensures the tree is balanced because both halves have roughly equal size.

How the Conversion Works — Step by Step

BST to sorted array via in-order traversal: 1. If current node is None, return. 2. Recursively traverse left subtree. 3. Append current node's value to result. 4. Recursively traverse right subtree. 5. The result list is sorted because BST property guarantees left < root < right.

Sorted array to balanced BST: 1. If array is empty, return None. 2. Find mid = len(array) // 2. 3. Create a TreeNode with value array[mid]. 4. node.left = recursively build from array[:mid]. 5. node.right = recursively build from array[mid+1:]. 6. Return node.

For array [1,2,3,4,5,6,7]: mid=3 (value 4) becomes root. Left subtree from [1,2,3]: mid=1 (value 2). Right subtree from [5,6,7]: mid=1 (value 6). This produces a perfectly balanced BST of height 2.

Worked Example — Tracing Both Directions

BST: 4 / \ 2 6 / \ / \ 1 3 5 7

In-order traversal → sorted array: 1. Go left from 4 to 2. Go left from 2 to 1. 1 has no children → append 1. 2. Back to 2 → append 2. Go right to 3 → append 3. 3. Back to 4 → append 4. Go right to 6. 4. Go left from 6 to 5 → append 5. Back to 6 → append 6. Right to 7 → append 7. 5. Result: [1,2,3,4,5,6,7].

Now reverse: sorted [1,2,3,4,5,6,7] → BST: - mid=3 → root=4. Left from [1,2,3]: mid=1 → root=2, left=1, right=3. - Right from [5,6,7]: mid=1 → root=6, left=5, right=7. - Tree is exactly the original BST above. Height = 2, perfectly balanced.

Implementation

Both directions are clean recursive implementations. BST to array uses in-order DFS. Array to BST uses divide-and-conquer, always picking the midpoint as root. The BST-to-array runs in O(n) time and O(n) space (result + call stack). The array-to-BST also runs in O(n) time and O(log n) stack space for a balanced input. An iterative in-order traversal using an explicit stack avoids recursion depth issues for very deep trees.

bst_sorted_array.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val; self.left = left; self.right = right

def bst_to_sorted_array(root):
    """In-order traversal → sorted list."""
    result = []
    def inorder(node):
        if not node:
            return
        inorder(node.left)
        result.append(node.val)
        inorder(node.right)
    inorder(root)
    return result

def sorted_array_to_bst(nums):
    """Sorted array → height-balanced BST."""
    if not nums:
        return None
    mid = len(nums) // 2
    node = TreeNode(nums[mid])
    node.left = sorted_array_to_bst(nums[:mid])
    node.right = sorted_array_to_bst(nums[mid+1:])
    return node

# Build BST manually and convert
root = TreeNode(4)
root.left = TreeNode(2, TreeNode(1), TreeNode(3))
root.right = TreeNode(6, TreeNode(5), TreeNode(7))

arr = bst_to_sorted_array(root)
print(arr)  # [1, 2, 3, 4, 5, 6, 7]

# Rebuild BST from sorted array
new_root = sorted_array_to_bst(arr)
print(bst_to_sorted_array(new_root))  # [1, 2, 3, 4, 5, 6, 7]
Output
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]

Production Considerations: Recursion Limits and Iterative Alternatives

Recursive in-order traversal is clean but dangerous in production. A degenerate BST (height = n) consumes O(n) call stack space. In Java, default stack size is often 1MB, which may overflow near 10,000–20,000 recursive calls depending on frame size. Iterative traversal using an explicit stack (Deque) offers predictable memory usage and avoids stack overflow regardless of tree shape. The iterative algorithm uses a while loop and a stack to simulate recursion: push left until null, pop, process, move right.

Java implementation: ``java public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); Deque<TreeNode> stack = new ArrayDeque<>(); TreeNode curr = root; while (curr != null || !stack.isEmpty()) { while (curr != null) { stack.push(curr); curr = curr.left; } curr = stack.pop(); result.add(curr.val); curr = curr.right; } return result; } `` This runs in O(n) time and O(h) extra space (stack). For production systems handling untrusted or unbalanced trees, prefer iterative traversal. For balanced trees, recursion is acceptable if stack monitors are in place.

Performance insight: Recursive traversal on a balanced tree of 1 million nodes uses ~log2(n) ≈ 20 stack frames, negligible. On a degenerate tree, it uses 1 million frames, likely crashing.

io/thecodeforge/InorderIterative.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package io.thecodeforge;

import java.util.*;

public class InorderIterative {
    public static List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode curr = root;
        while (curr != null || !stack.isEmpty()) {
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
            curr = stack.pop();
            result.add(curr.val);
            curr = curr.right;
        }
        return result;
    }
}
Production Insight
Recursive traversal is elegant but dangerous on unbalanced trees.
Degenerate BSTs from sorted input are common in production (bulk imports).
Always prefer iterative traversal for unknown or large input distributions.
Key Takeaway
Recursive in-order is clean but O(n) stack.
Iterative Deque-based traversal is production-safe.
Choose based on input trust – unknown input => iterative.
When to Use Recursive vs Iterative In-Order
IfTree is guaranteed balanced (e.g., AVL, Red-Black)
UseRecursive is safe and cleaner.
IfTree height could be large (unknown input)
UseUse iterative traversal to avoid stack overflow.
IfTree is built from sorted array
UseDegenerate unless rebalanced – use iterative.
IfIn an interview
UseStart with recursive, then discuss iterative as production improvement.

Edge Cases: Duplicates, Null Input, and BST Validation

BST to sorted array conversion assumes a valid BST. Edge cases include: - Null root: return empty list. - Duplicate values: BST property typically enforces strict left < root < right. If duplicates are allowed (non-strict), the sorted array may contain consecutive equal values. Ensure insertion policy is consistent. - Single node: return [value]. - Tree with only left children: degenerate left-skewed – works fine but recursion depth may be high. - Tree with only right children: same.

Validation: Before trusting traversal output, validate the BST with in-order check or recursive bounds. A common bug is assuming the tree is a valid BST when it isn't.

Performance insight: Validating BST via in-order takes O(n) time and O(h) space, same as conversion.

bst_validation.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def is_valid_bst(root):
    prev = None
    stack = []
    curr = root
    while stack or curr:
        while curr:
            stack.append(curr)
            curr = curr.left
        curr = stack.pop()
        if prev is not None and curr.val <= prev:
            return False
        prev = curr.val
        curr = curr.right
    return True
Production trap: Assuming tree is valid
In production, data corruption or insertion errors can break BST invariant. Always validate the BST before relying on sorted output. A single mis-inserted node can produce a deceptively sorted array until the violation is hit.
Production Insight
BST validation is cheap insurance.
Degenerate trees are not invalid – they just have height n.
A non-valid BST produces silently wrong sorted output.
Add a validation assertion in debug mode or during integration tests.
Key Takeaway
Always validate BST property before traversal.
Duplicates require explicit policy.
Null input should return empty array.
● Production incidentPOST-MORTEMseverity: high

Production Incident: OutOfMemory from BST In-Order Traversal on Large Dataset

Symptom
Service crashes with StackOverflowError when exporting data from a BST containing over 10,000 nodes built from already-sorted input.
Assumption
The BST was assumed to be balanced because insertion used a standard insert method, but the input data happened to be pre-sorted.
Root cause
Standard BST insertion of sorted data creates a degenerate tree (height = n). Recursive in-order traversal uses O(n) stack space, causing stack overflow.
Fix
Switch to iterative in-order traversal using an explicit stack, or rebalance the tree periodically using DSW algorithm or by rebuilding from sorted array.
Key lesson
  • Always validate tree balance for recursive traversals in production.
  • Use iterative traversal for unknown or untrusted input distributions.
  • Monitor stack depth for recursive algorithms on large datasets.
Production debug guideSymptom-to-action guide for BST traversal failures3 entries
Symptom · 01
StackOverflowError during traversal
Fix
Check tree height; if height > 1000, switch to iterative traversal. Use ulimit -s to check stack size limit.
Symptom · 02
Traversal produces wrong order (e.g., not sorted)
Fix
Verify BST property by performing an in-order traversal and checking strictly increasing output. If violated, the BST is invalid – run validation algorithm.
Symptom · 03
Traversal times out for large trees
Fix
Profile with perf or visualvm. If recursive, switch to iterative. If tree is balanced but still slow, check for infinite loop in custom traversal logic.
★ Quick Debug Cheat Sheet: BST Traversal FailuresCommon traversal failure symptoms and immediate fixes.
StackOverflowError
Immediate action
Switch to iterative traversal immediately
Commands
java -Xss2m (increase stack size) – temporary fix
Implement iterative version using Deque (ArrayDeque)
Fix now
Replace recursion with explicit stack
Output not sorted+
Immediate action
Run BST validation check
Commands
In-order traverse and compare each node to previous
Find the offending node and re-insert correctly
Fix now
Rebuild BST from validated data
Traversal too slow+
Immediate action
Check for O(n^2) behavior (e.g., repeated traversal)
Commands
Profile with JProfiler or async-profiler
Cache traversal results if tree is static
Fix now
Use iterative traversal with early exit if partial order needed
AspectRecursive In-OrderIterative In-Order
Code readabilityVery clean — mirrors the definition directlyMore verbose — explicit stack management
Risk of StackOverflowYes — on degenerate trees (height = n)No — uses heap-allocated Deque instead
Space complexity (extra)O(h) implicit call stack; O(n) worst caseO(h) explicit Deque; O(n) worst case
Time complexityO(n) — visits each node onceO(n) — visits each node once
Best forBalanced trees, interviews, prototypingProduction code, unknown input distributions
DebuggabilityHarder — stack frames aren't directly inspectableEasier — you can inspect the Deque at any point
Tail-call optimizationJava does NOT optimize tail calls — no benefit hereN/A — no recursion to optimize

Key takeaways

1
In-order traversal of a BST produces elements in sorted ascending order.
2
A balanced BST from a sorted array is built by recursively choosing the middle element as root.
3
Both conversions run in O(n) time.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

FAQ · 3 QUESTIONS

Frequently Asked Questions

01
Why does in-order traversal of a BST give sorted output?
02
How do you verify a BST is valid after construction?
03
What is the height of a BST built from a sorted array of n elements?
🔥

That's Trees. Mark it forged?

4 min read · try the examples if you haven't

Previous
Diameter of Binary Tree
13 / 15 · Trees
Next
Serialize and Deserialize Binary Tree