Launch your tech mastery with us—your coding journey starts now!
Course Content
Data Structure

B-Trees

A B-Tree is a self-balancing search tree designed for systems that read and write large blocks of data, like databases and file systems.

B-Tree data structure illustration showing nodes containing multiple keys and multiple children, organized in balanced hierarchical levels for efficient large data storage and searching.

How a B-Tree Works

A B-Tree is a “fat” search tree designed to handle massive amounts of data. Unlike a binary tree where nodes only have one key and two children, a B-Tree node can hold multiple keys and have many children.

  • Self-Balancing: It automatically keeps itself perfectly balanced. All leaf nodes (the bottom of the tree) are always on the exact same level.
  • Disk-Optimized: It is built to minimize slow disk reads by packing as much data into a single node (or “block”) as possible, reading huge chunks of data at once rather than node-by-node.

Real-Life Examples

  • A Library Filing Cabinet: Instead of choosing between just “left” or “right,” you open a drawer containing files “A through G.” Inside, you find folders splitting the data further, drastically reducing the number of steps to find a single paper among thousands.

Technical Applications

  • Databases: Both SQL and NoSQL databases heavily rely on B-Trees (specifically a variation called B+ Trees) to build their indexes, allowing them to instantly locate a specific row among millions without scanning the whole table.
  • File Systems: Operating systems (like Windows NTFS or Linux Ext4) use B-Trees to quickly look up where exactly a file’s data is physically stored on your hard drive.

Time and Space Complexity

  • Time Complexity: O(log n) for searching, inserting, and deleting. The tree is exceptionally shallow and wide, meaning it takes very few steps to reach the bottom.
  • Space Complexity: O(n) Memory scales with the amount of data stored.

Properties of B-Tree of order M

  1. Every node has at most M children
  2. Every non-leaf node (except root) has at least ⌈M/2⌉ children
  3. The root has at least 2 children (if it’s not a leaf)
  4. All leaves are at the same level
  5. A non-leaf node with k children contains k-1 keys

B-Tree Implementation (Order 3)

Code Example:
Java

import java.util.*;

// B-Tree Node
class BTreeNode {

    List<Integer> keys = new ArrayList<>();     // keys in node
    List<BTreeNode> children = new ArrayList<>(); // child pointers
    int t;        // minimum degree
    boolean leaf; // true if leaf node

    BTreeNode(int t, boolean leaf) {
        this.t = t;
        this.leaf = leaf;
    }

    // Traverse all nodes
    void traverse() {

        int i;

        for (i = 0; i < keys.size(); i++) {

            if (!leaf)
                children.get(i).traverse();

            System.out.print(keys.get(i) + " ");
        }

        if (!leaf)
            children.get(i).traverse();
    }

    // Search key
    BTreeNode search(int key) {

        int i = 0;

        while (i < keys.size() && key > keys.get(i))
            i++;

        if (i < keys.size() && keys.get(i) == key)
            return this;

        if (leaf)
            return null;

        return children.get(i).search(key);
    }

    // Insert into non-full node
    void insertNonFull(int key) {

        int i = keys.size() - 1;

        if (leaf) {

            keys.add(0);

            while (i >= 0 && keys.get(i) > key) {
                keys.set(i + 1, keys.get(i));
                i--;
            }

            keys.set(i + 1, key);
        }

        else {

            while (i >= 0 && keys.get(i) > key)
                i--;

            if (children.get(i + 1).keys.size() == 2 * t - 1) {

                splitChild(i + 1, children.get(i + 1));

                if (keys.get(i + 1) < key)
                    i++;
            }

            children.get(i + 1).insertNonFull(key);
        }
    }

    // Split child node
    void splitChild(int i, BTreeNode y) {

        BTreeNode z = new BTreeNode(y.t, y.leaf);

        for (int j = 0; j < t - 1; j++)
            z.keys.add(y.keys.get(j + t));

        if (!y.leaf)
            for (int j = 0; j < t; j++)
                z.children.add(y.children.get(j + t));

        y.keys.subList(t, y.keys.size()).clear();

        if (!y.leaf)
            y.children.subList(t, y.children.size()).clear();

        children.add(i + 1, z);

        keys.add(i, y.keys.remove(t - 1));
    }
}

// B-Tree
class BTree {

    BTreeNode root;
    int t;

    BTree(int t) {
        this.t = t;
        root = null;
    }

    // Traverse tree
    void traverse() {

        if (root != null)
            root.traverse();

        System.out.println();
    }

    // Search key
    BTreeNode search(int key) {

        if (root == null)
            return null;

        return root.search(key);
    }

    // Insert key
    void insert(int key) {

        if (root == null) {

            root = new BTreeNode(t, true);
            root.keys.add(key);
            return;
        }

        if (root.keys.size() == 2 * t - 1) {

            BTreeNode s = new BTreeNode(t, false);

            s.children.add(root);

            s.splitChild(0, root);

            int i = 0;

            if (s.keys.get(0) < key)
                i++;

            s.children.get(i).insertNonFull(key);

            root = s;
        }

        else
            root.insertNonFull(key);
    }

    // Demo
    public static void main(String[] args) {

        BTree tree = new BTree(3);

        System.out.println("Insert: 10 20 5 6 12 30 7 17");

        tree.insert(10);
        tree.insert(20);
        tree.insert(5);
        tree.insert(6);
        tree.insert(12);
        tree.insert(30);
        tree.insert(7);
        tree.insert(17);

        System.out.println("Traversal:");
        tree.traverse();

        int key = 6;
        System.out.println("Search " + key + ": " +
                (tree.search(key) != null ? "Found" : "Not Found"));

        key = 15;
        System.out.println("Search " + key + ": " +
                (tree.search(key) != null ? "Found" : "Not Found"));
    }
}