Flatten a Binary Search Tree into a Sorted List

Problem and examples

Given a binary search tree (BST), flatten it into a sorted list of values. A BST is a tree data structure where for each node, all nodes in the left subtree have smaller values and all nodes in the right subtree have larger values.

Your task is to return a list of integers representing the values of the BST in ascending order.

This problem is commonly solved using in-order traversal, which naturally visits the nodes in sorted order in a BST.

Input BST Flattened Sorted List Description
[5, 3, 7, 2, 4, 6, 8] [2, 3, 4, 5, 6, 7, 8] In-order traversal of a balanced BST yields sorted list of values from smallest to largest.
[10, 5, 15, 3, 7, null, 18] [3, 5, 7, 10, 15, 18] Standard BST with missing left child under 15. In-order traversal gives correct sorted order.
[1, null, 2, null, 3] [1, 2, 3] Right-skewed BST behaves like a sorted linked list. In-order traversal confirms order.
[3, 2, null, 1] [1, 2, 3] Left-skewed BST. In-order traversal still results in ascending order.
[42] [42] Single-node BST. Flattened result is a single-element list.
[] [] Empty BST. The flattened sorted list is also empty.

Explore Flatten a Binary Search Tree into a Sorted List

Load an example or enter your own input. Use the player controls to follow each change.

Understanding the Problem

We are given a Binary Search Tree (BST), and the goal is to flatten it into a sorted list. That means we want to convert the hierarchical structure of the BST into a simple array that contains all the node values in increasing order.

Why does this work well with a BST? Because a BST has a special property: for every node, all values in the left subtree are smaller, and all values in the right subtree are greater. So, if we perform an in-order traversal (Left → Node → Right), we naturally visit the nodes in ascending order.

Step-by-Step Solution with Example

step 1: Choose a suitable traversal

We need a way to visit all nodes in increasing order. The best traversal for this is in-order traversal, which processes the left subtree, then the current node, and then the right subtree.

step 2: Understand how in-order traversal behaves on a BST

Let's take an example BST:


        5
       /       3   7
     /        2   4   9

The in-order traversal for this tree will visit the nodes in this order: 2, 3, 4, 5, 7, 9. This is exactly the sorted order we want.

step 3: Implement a recursive in-order traversal

We'll use a helper function that traverses the tree in in-order fashion and appends each node's value to a result list.

step 4: Combine the results into a single sorted list

After the traversal is complete, the result list will contain all values in sorted order. This becomes our flattened version of the BST.

Edge Cases

Empty Tree

If the BST is null or empty, we simply return an empty list: []. There are no nodes to process.

Single-node Tree

If the tree contains only one node, say 5, then the result list will be [5]. The traversal works correctly even in this minimal case.

Left-skewed Tree

Consider a tree where every node only has a left child, like this:


    4
   /
  3
 /
2

The in-order traversal would be: 2, 3, 4. Still sorted — no special handling needed.

Right-skewed Tree

For a tree where each node has only a right child:


1
   2
       3

The in-order traversal gives: 1, 2, 3, again correctly sorted.

Finally

Flattening a BST into a sorted list becomes straightforward once we recognize the power of in-order traversal. It leverages the inherent structure of the BST to extract elements in order without any additional sorting steps.

By carefully handling edge cases like empty trees or skewed trees, we ensure the solution is robust and beginner-friendly.

This technique is efficient and commonly used in many coding interviews and real-world systems where sorted access to tree data is required.

  1. If the tree is empty, return an empty list.
  2. Perform an in-order traversal of the binary search tree.
  3. Visit the left subtree, then the current node, and finally the right subtree.
  4. Collect the node values in order; due to BST properties, this will yield a sorted list.
  5. Return the collected list of values.

Implementation and efficiency

C implementation

#include <stdio.h>
#include <stdlib.h>

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

void inorder(struct TreeNode* node) {
    if (node) {
        inorder(node->left);
        printf("%d ", node->val);
        inorder(node->right);
    }
}

struct TreeNode* createNode(int val) {
    struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    node->val = val;
    node->left = node->right = NULL;
    return node;
}

int main() {
    struct TreeNode* root = createNode(4);
    root->left = createNode(2);
    root->right = createNode(6);
    root->left->left = createNode(1);
    root->left->right = createNode(3);
    root->right->left = createNode(5);
    root->right->right = createNode(7);

    inorder(root);
    return 0;
}

C++ implementation

#include <iostream>
using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

void inorder(TreeNode* node) {
    if (node) {
        inorder(node->left);
        cout << node->val << " ";
        inorder(node->right);
    }
}

int main() {
    TreeNode* root = new TreeNode(4);
    root->left = new TreeNode(2);
    root->right = new TreeNode(6);
    root->left->left = new TreeNode(1);
    root->left->right = new TreeNode(3);
    root->right->left = new TreeNode(5);
    root->right->right = new TreeNode(7);

    inorder(root);
    return 0;
}

Python implementation

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def flatten_bst(root):
    result = []
    def inorder(node):
        if node:
            inorder(node.left)
            result.append(node.val)
            inorder(node.right)
    inorder(root)
    return result

if __name__ == '__main__':
    root = TreeNode(4, TreeNode(2, TreeNode(1), TreeNode(3)), TreeNode(6, TreeNode(5), TreeNode(7)))
    print(flatten_bst(root))

Java implementation

class TreeNode {
    int val;
    TreeNode left, right;
    TreeNode(int val) {
        this.val = val;
    }
}

public class FlattenBST {
    public static void inorder(TreeNode node) {
        if (node != null) {
            inorder(node.left);
            System.out.print(node.val + " ");
            inorder(node.right);
        }
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode(4);
        root.left = new TreeNode(2);
        root.right = new TreeNode(6);
        root.left.left = new TreeNode(1);
        root.left.right = new TreeNode(3);
        root.right.left = new TreeNode(5);
        root.right.right = new TreeNode(7);

        inorder(root);
    }
}

JavaScript implementation

class TreeNode {
    constructor(val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}

function inorder(node, result) {
    if (node) {
        inorder(node.left, result);
        result.push(node.val);
        inorder(node.right, result);
    }
}

const root = new TreeNode(4);
root.left = new TreeNode(2);
root.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.left = new TreeNode(5);
root.right.right = new TreeNode(7);

const result = [];
inorder(root, result);
console.log(result);

Go implementation

package main

import "fmt"

type TreeNode struct {
    val   int
    left  *TreeNode
    right *TreeNode
}

func inorder(node *TreeNode, result *[]int) {
    if node != nil {
        inorder(node.left, result)
        *result = append(*result, node.val)
        inorder(node.right, result)
    }
}

func main() {
    root := &TreeNode{val: 4}
    root.left = &TreeNode{val: 2}
    root.right = &TreeNode{val: 6}
    root.left.left = &TreeNode{val: 1}
    root.left.right = &TreeNode{val: 3}
    root.right.left = &TreeNode{val: 5}
    root.right.right = &TreeNode{val: 7}

    result := []int{}
    inorder(root, &result)
    fmt.Println(result)
}

Rust implementation

struct TreeNode {
    val: i32,
    left: Option<Box<TreeNode>>,
    right: Option<Box<TreeNode>>,
}

fn inorder(node: &Option<Box<TreeNode>>, result: &mut Vec<i32>) {
    if let Some(n) = node {
        inorder(&n.left, result);
        result.push(n.val);
        inorder(&n.right, result);
    }
}

fn main() {
    let root = Some(Box::new(TreeNode {
        val: 4,
        left: Some(Box::new(TreeNode {
            val: 2,
            left: Some(Box::new(TreeNode { val: 1, left: None, right: None })),
            right: Some(Box::new(TreeNode { val: 3, left: None, right: None })),
        })),
        right: Some(Box::new(TreeNode {
            val: 6,
            left: Some(Box::new(TreeNode { val: 5, left: None, right: None })),
            right: Some(Box::new(TreeNode { val: 7, left: None, right: None })),
        })),
    }));

    let mut result = Vec::new();
    inorder(&root, &mut result);
    println!("{:?}", result);
}

Kotlin implementation

class TreeNode(var val: Int) {
    var left: TreeNode? = null
    var right: TreeNode? = null
}

fun inorder(node: TreeNode?, result: MutableList<Int>) {
    if (node != null) {
        inorder(node.left, result)
        result.add(node.val)
        inorder(node.right, result)
    }
}

fun main() {
    val root = TreeNode(4)
    root.left = TreeNode(2)
    root.right = TreeNode(6)
    root.left?.left = TreeNode(1)
    root.left?.right = TreeNode(3)
    root.right?.left = TreeNode(5)
    root.right?.right = TreeNode(7)

    val result = mutableListOf<Int>()
    inorder(root, result)
    println(result)
}

Swift implementation

class TreeNode {
    var val: Int
    var left: TreeNode?
    var right: TreeNode?
    init(_ val: Int) {
        self.val = val
        self.left = nil
        self.right = nil
    }
}

func inorder(_ node: TreeNode?, _ result: inout [Int]) {
    if let node = node {
        inorder(node.left, &result)
        result.append(node.val)
        inorder(node.right, &result)
    }
}

let root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(6)
root.left?.left = TreeNode(1)
root.left?.right = TreeNode(3)
root.right?.left = TreeNode(5)
root.right?.right = TreeNode(7)

var result: [Int] = []
inorder(root, &result)
print(result)

TypeScript implementation

class TreeNode {
    val: number;
    left: TreeNode | null = null;
    right: TreeNode | null = null;
    constructor(val: number) {
        this.val = val;
    }
}

function inorder(node: TreeNode | null, result: number[]): void {
    if (node) {
        inorder(node.left, result);
        result.push(node.val);
        inorder(node.right, result);
    }
}

const root = new TreeNode(4);
root.left = new TreeNode(2);
root.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.left = new TreeNode(5);
root.right.right = new TreeNode(7);

const result: number[] = [];
inorder(root, result);
console.log(result);