Skip to content

Expert · Data structures in C · topic 49 of 60 · 30 min

Binary search trees

Explanation

A binary search tree (BST) is made of nodes with a value and left and right child pointers; every value in the left subtree is smaller and every value in the right subtree is larger. Search and insert follow one path from the root, which takes O(log n) when the tree is balanced but O(n) if it degenerates into a chain. An in-order traversal visits the values in sorted order.

The shape

output
typedef struct TreeNode {
    int key;
    struct TreeNode *left, *right;
} TreeNode;

            50
          /    \
        30      70
       /  \       \
     20    40      80

every key in 50's left subtree (20, 30, 40) < 50 < every key in its right subtree (70, 80)
c
TreeNode *insert(TreeNode *root, int key) {
    if (root == NULL) {
        TreeNode *n = malloc(sizeof *n);
        if (!n) return NULL;                    /* real code should report this */
        n->key = key;
        n->left = n->right = NULL;
        return n;
    }
    if (key < root->key) root->left = insert(root->left, key);
    else if (key > root->key) root->right = insert(root->right, key);
    /* equal keys: ignored in this simple version */
    return root;
}

int contains(const TreeNode *root, int key) {
    while (root) {
        if (key == root->key) return 1;
        root = (key < root->key) ? root->left : root->right;   /* go one way only */
    }
    return 0;
}

In-order traversal gives sorted output

c
void in_order(const TreeNode *t) {
    if (!t) return;
    in_order(t->left);              /* smaller keys first */
    printf("%d ", t->key);
    in_order(t->right);             /* then larger keys */
}
/* for the tree above: 20 30 40 50 70 80 */

Pre-order (node, left, right) is used to copy a tree; post-order (left, right, node) is used to free one, because children must be freed before their parent.

c
void free_tree(TreeNode *t) {
    if (!t) return;
    free_tree(t->left);
    free_tree(t->right);
    free(t);                        /* post-order: the node last */
}

int height(const TreeNode *t) {
    if (!t) return 0;
    int l = height(t->left), r = height(t->right);
    return 1 + (l > r ? l : r);
}

Balance matters

output
inserting 10, 20, 30, 40, 50 in sorted order:
10
  \
   20
     \
      30          ← a "tree" that is really a linked list: height 5, search O(n)
        \
         40
           \
            50
Careful: A plain BST is only fast when it stays roughly balanced. Inserting already-sorted data (very common in practice, for example IDs that increase) degrades it to a linked list. Production code uses self-balancing trees (AVL, red-black: used inside the Linux kernel and C++ std::map) or a hash table when ordering is not needed.
Think of it like this: Searching a BST is like the "higher or lower" guessing game with a well-organised friend: at each step the answer tells you to go left (lower) or right (higher), and you never look at the other half. If the friend arranged numbers badly (sorted in a line), you would have to ask about every number.
Tip: Recursion is natural for trees, but very deep (unbalanced) trees can overflow the stack. contains above uses a loop for that reason; you can write insert iteratively too.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Binary search trees · 1/6

Binary search trees

In this lesson you will build a binary search tree.

Prefer a video by a teacher? Find free videos on “binary search tree in c insert search inorder traversal” on YouTube ↗

In real life: An autocomplete dictionary for a keyboard app

A simple Indian-language keyboard prototype stored its word list in a BST keyed by word, so it could find words and list them in alphabetical order with an in-order walk. When the word list was loaded from a sorted file, the tree became a chain and lookups slowed down badly; inserting the words in shuffled order (and later switching to a balanced tree) fixed it.

c
typedef struct WordNode { char word[32]; struct WordNode *left, *right; } WordNode;
/* insert/contains as above, comparing with strcmp(a, b) < 0 instead of a < b */

Practice (0/3 done)

Task 1 · Question

Insert 8, 3, 10, 1, 6 into an empty BST (in that order). What does an in-order traversal print?

Task 2 · Code · Javascript

The same BST algorithm in JavaScript, which runs here: write insert(root, key) (returns the root; nodes are { key, left, right } with null children; ignore duplicates), inOrder(root) returning an array of keys, and height(root) (an empty tree has height 0).

Task 3 · Practice

Implement a BST of ints in C with insert, contains (iterative), in_order printing, height, count_nodes, find_min and free_tree. Insert 15 random numbers and then 15 sorted numbers into two trees and print both heights; explain the difference.

Quick quiz

Question 1

1.In a BST, where are keys smaller than a node's key?

Question 2

2.What is the worst-case search time in an unbalanced BST?

Question 3

3.Which traversal frees a tree safely?

Question 4

4.What does an in-order traversal of a BST produce?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

In a BST, where are keys smaller than a node's key?

Answer: In its left subtree

That is the BST property.

What is the worst-case search time in an unbalanced BST?

Answer: O(n)

A chain must be walked node by node.

Which traversal frees a tree safely?

Answer: Post-order

Children must be freed before the parent.

What does an in-order traversal of a BST produce?

Answer: Sorted order

Left, node, right.

Which traversal of a BST lists its values in increasing order?Related

Answer: Inorder

Left subtree (smaller), node, right subtree (larger), applied at every node, gives sorted order.

From Binary search trees

Which traversal records a node only after both of its subtrees?Related

Answer: Postorder

Postorder is left, right, node, so children are finished before the parent, which is what deleting or sizing needs.

From Traversals: DFS and BFS

What is the extra space of a recursive tree function on a balanced tree of n nodes?Related

Answer: O(log n)

The recursion stack holds one path from the root, and a balanced tree has height O(log n).

From Recursive tree patterns

Why do databases use B-trees for indexes instead of binary search trees?Related

Answer: Each B-tree node holds many keys, so the tree is shallow and a lookup reads only a few disk pages

Disk reads come in pages; a wide node fills a page, so a few levels cover millions of rows.

From Lowest common ancestor, serialisation and balanced trees

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Data structures in C” before its exam: Hash tables.
  2. Module 10 exam: Data structures in C · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Debugging and tools. 60 topics left in the course before the final exam.

← Previous: Queues and circular buffers