Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Data Structures & Algorithms (DSA)  Module 9 – Trees and binary search trees

Binary search trees: search, insert, delete

How the search-tree ordering makes search, insert and delete one walk from the root, the three deletion cases, and why sorted input builds a path.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free core, Pro depth: 10 of 30 minutes free
Free: The invariant · Search and insert, traced · Delete: three cases · 3 more sections. With a pass: 3 in-depth parts and 3 interview answers, about 20 minutes.

What you will learn

  • Maintain the BST ordering invariant through insertions and deletions
  • Delete nodes with zero, one and two children
  • Validate a BST and find floor, ceiling and k-th smallest

Before you start

A binary search tree (BST) keeps its keys in order: a node’s key is larger than all the keys below it on the left and smaller than all the keys below it on the right. That one rule turns search into a single walk from the root: compare, go left or right, and stop at the key or at an empty place. Insertion makes the same walk and attaches the new key where it fell off the tree. Deletion has three cases, decided by how many children the node has. Each of these operations costs O(h) for a tree of height h. That is about log2 n when the tree stays bushy, but n − 1 when the keys arrive in sorted order, as the measurements below show. And because of the rule, an inorder traversal lists the keys in increasing order.

The invariant

NIST’s Dictionary of Algorithms and Data Structures defines a binary search tree as a binary tree in which every node’s left subtree holds smaller keys and its right subtree larger ones. The rule applies to whole subtrees, not only to a node’s two children: every key below 30 on the left of 50 must also be smaller than 50. Each key is stored once in this lesson, so inserting a key that is already present changes nothing. Because the left subtree holds the smaller keys and the right one the larger, inorder visits a search tree’s keys in sorted order.

Search and insert, traced

Search, insert and the three cases of delete on one tree Python · basics/bst.py
"""A binary search tree: search, insert and the three cases of delete, with the tree printed after each step."""


class Node:
    def __init__(self, key):
        self.key, self.left, self.right = key, None, None


def search(root, key, path):
    """Walks down from the root; path collects the keys compared on the way."""
    node = root
    while node is not None:
        path.append(node.key)
        if key == node.key:
            return node
        node = node.left if key < node.key else node.right
    return None


def insert(node, key):
    """Returns the subtree with key added; an existing key is left alone (each key is stored once)."""
    if node is None:
        return Node(key)
    if key < node.key:
        node.left = insert(node.left, key)
    elif key > node.key:
        node.right = insert(node.right, key)
    return node


def delete(node, key):
    """Returns the subtree with key removed."""
    if node is None:
        return None                              # the key is not in the tree
    if key < node.key:
        node.left = delete(node.left, key)
    elif key > node.key:
        node.right = delete(node.right, key)
    elif node.left is None:                      # no child, or only a right child: the child takes the node's place
        return node.right
    elif node.right is None:                     # only a left child
        return node.left
    else:                                        # two children: take the inorder successor's key, delete it below
        successor = node.right
        while successor.left is not None:
            successor = successor.left
        node.key = successor.key
        node.right = delete(node.right, successor.key)
    return node


def inorder(node, out):
    if node:
        inorder(node.left, out)
        out.append(node.key)
        inorder(node.right, out)
    return out


def shape(node):
    """The tree as nested brackets: key(left, right), with - for an empty child."""
    if node is None:
        return "-"
    if node.left is None and node.right is None:
        return str(node.key)
    return f"{node.key}({shape(node.left)}, {shape(node.right)})"


root = None
for k in (50, 30, 70, 20, 40, 60, 80, 55, 65):
    root = insert(root, k)
print("tree:", shape(root))
for key in (65, 58):
    path = []
    found = search(root, key, path)
    print(f"search {key}: compared {path}, {'found' if found else 'not found'}")
root = insert(root, 58)
print("after insert 58:", shape(root))
for key, case in ((20, "a leaf"), (55, "one child"), (50, "two children")):
    root = delete(root, key)
    print(f"after delete {key} ({case}):", shape(root))
print("inorder:", inorder(root, []))

Output

tree: 50(30(20, 40), 70(60(55, 65), 80))
search 65: compared [50, 70, 60, 65], found
search 58: compared [50, 70, 60, 55], not found
after insert 58: 50(30(20, 40), 70(60(55(-, 58), 65), 80))
after delete 20 (a leaf): 50(30(-, 40), 70(60(55(-, 58), 65), 80))
after delete 55 (one child): 50(30(-, 40), 70(60(58, 65), 80))
after delete 50 (two children): 58(30(-, 40), 70(60(-, 65), 80))
inorder: [30, 40, 58, 60, 65, 70, 80]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bst.py

A search for 65 compares it with 50, 70, 60 and 65: right, left, right, found. A search for 58 compares it with 50, 70, 60 and 55 and then reaches an empty place, so 58 is not in the tree, and that empty place, the right child of 55, is exactly where an insertion puts it. Insertion never moves an existing key, so it keeps the invariant: the new key lies between the same bounds as the empty place it fills.

Delete: three cases

Two search trees: before, 50 is the root with two children; after deleting it, 55, the smallest key on its right, is the root.Before: delete 50After: 55 moved up, its old node removed806555 (successor)6040207030508065604020703055rightleftrightleftrightleftrightleftrightrightleftrightleftrightleftcopy 55 into the root, then delete the leaf 55

Deleting a key with two children by moving up its inorder successor

Text description of the diagram

The diagram shows the same binary search tree before and after deleting its root, 50, which has two children. Edges are labelled left and right.

  1. Before: 50 has a left child 30 (with children 20 and 40) and a right child 70 (with children 60 and 80). 60 has a left child 55 and a right child 65. The inorder successor of 50 is 55, the smallest key in its right subtree, found by going right once and then left as far as possible.
  2. The key 55 is copied into the root, and the node that held 55 is removed. That node had no left child, so removing it is one of the easy cases.
  3. After: 55 is the root, with 30 (children 20 and 40) on its left and 70 (children 60 and 80) on its right; 60 now has only a right child, 65. Every key on the left is still smaller than 55 and every key on the right larger.
  1. No children: remove the node. Deleting 20 just empties 30’s left child.
  2. One child: the child takes the node’s place. Deleting 55, whose only child is 58, puts 58 under 60.
  3. Two children: copy in the key of the node’s inorder successor, the smallest key of its right subtree, then delete the successor’s old node. The successor is the leftmost node of the right subtree, so it has no left child, and removing it is case 1 or case 2.

The successor is the right replacement because it is the next key in sorted order: larger than every key on the left, and smaller than every other key on the right. The run deletes 50 this way, 58 takes its place, and the inorder list stays sorted.

How tall the tree gets, measured

4,096 insertions: random order against sorted order Python · heights/heights.py
"""The height of a binary search tree after 4,096 insertions: keys in random order against keys in sorted order."""
import random


class Node:
    __slots__ = ("key", "left", "right")

    def __init__(self, key):
        self.key, self.left, self.right = key, None, None


def insert(root, key):
    """Walks down from the root without recursion and attaches the key where the search fell off the tree."""
    if root is None:
        return Node(key)
    node = root
    while True:
        if key < node.key:
            if node.left is None:
                node.left = Node(key)
                return root
            node = node.left
        elif key > node.key:
            if node.right is None:
                node.right = Node(key)
                return root
            node = node.right
        else:
            return root                      # already present: this tree keeps each key once


def height_and_depths(root):
    """Height in edges and the average depth of a node (the comparisons a search for a stored key makes, minus one)."""
    total, height, level, depth = 0, -1, [root], 0
    while level:
        height += 1
        total += depth * len(level)
        level = [c for n in level for c in (n.left, n.right) if c]
        depth += 1
    return height, total


N = 4_096
rng = random.Random(4096)
keys = list(range(N))
shuffled = keys[:]
rng.shuffle(shuffled)
for label, order in (("random order", shuffled), ("sorted order", keys)):
    root = None
    for k in order:
        root = insert(root, k)
    h, total = height_and_depths(root)
    print(f"{N:,} keys in {label}: height {h:,}, average depth {total / N:,.2f}")

heights, depths = [], []
for _ in range(200):
    rng.shuffle(shuffled)
    root = None
    for k in shuffled:
        root = insert(root, k)
    h, total = height_and_depths(root)
    heights.append(h)
    depths.append(total / N)
print(f"200 random orders: height from {min(heights)} to {max(heights)}, mean {sum(heights) / 200:.2f};"
      f" average depth {sum(depths) / 200:.2f}")
print(f"for comparison: floor(log2 {N:,}) = {N.bit_length() - 1}, the lowest possible height; {N - 1:,}, the highest")

Output

4,096 keys in random order: height 23, average depth 13.09
4,096 keys in sorted order: height 4,095, average depth 2,047.50
200 random orders: height from 23 to 36, mean 26.61; average depth 13.82
for comparison: floor(log2 4,096) = 12, the lowest possible height; 4,095, the highest

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 heights.py

The same 4,096 keys built a tree of height 23 in random order and 4,095 in sorted order, where every key became the right child of the one before. Over 200 random orders the height ranged from 23 to 36, with a mean of 26.61, while the lowest possible height is 12. The average depth decides what a search for a stored key costs: about 13.82 for random orders against 2,047.5 for sorted input, so the same lookup took about 15 comparisons in one tree and about 2,048 in the other.

Binary search tree of n keys and height h
Operation Time Extra space Note
search, insert, delete O(h) O(1) walking, O(h) recursing h is about log2 n when bushy, n − 1 for a path
minimum, maximum, successor O(h) O(1) walk left, walk right, or climb
inorder listing O(n) O(h) the keys in sorted order

Built on the same invariant

Validating a tree passes a lower and an upper bound down from the root, because comparing each node only with its children misses bad trees. Floor and ceiling find the nearest key below or above a value in one walk. The k-th smallest key comes from an inorder walk that stops early. Balanced trees such as AVL and red-black trees keep the height near log2 n, and Java’s TreeMap is a red-black tree.

Exercise: a search tree of your own

The exercise asks for insert, delete, contains and inorder, checked on each deletion case and on 3,000 random operations against a plain set.

Exercise · Medium · Python, JavaScript

A binary search tree with insert, delete, contains and inorder

Complete the class SearchTree, a binary search tree of distinct integer keys built from Node objects (key, left, right). The tree starts empty (root is None; JavaScript: null).

  • insert(key) adds the key; inserting a key that is already there changes nothing.
  • contains(key) returns whether the key is in the tree.
  • delete(key) removes the key if it is there and does nothing otherwise. A node with two children takes the key of its inorder successor, the smallest key in its right subtree, and that successor's node is removed instead.
  • inorder() returns all keys in increasing order, as a list (JavaScript: an array).

The tests check each deletion case on the lesson's tree, deletion of the root, and 3,000 random operations against a plain set. They also read root to check that a two-child deletion used the successor.

Python · Starter code · search_tree.py

class Node:
    def __init__(self, key):
        self.key, self.left, self.right = key, None, None


class SearchTree:
    """A binary search tree of distinct keys."""

    def __init__(self):
        self.root = None

    def insert(self, key):
        raise NotImplementedError("write insert")

    def contains(self, key):
        raise NotImplementedError("write contains")

    def delete(self, key):
        raise NotImplementedError("write delete")

    def inorder(self):
        raise NotImplementedError("write inorder")
The sample tests · test_search_tree.py
import random

from search_tree import SearchTree


def lesson_tree():
    t = SearchTree()
    for k in (50, 30, 70, 20, 40, 60, 80, 55, 65):
        t.insert(k)
    return t


def test_insert_and_inorder():
    """inorder lists the keys in increasing order, and a repeated insert changes nothing"""
    t = lesson_tree()
    t.insert(40)
    assert t.inorder() == [20, 30, 40, 50, 55, 60, 65, 70, 80]
    assert t.root.key == 50 and t.root.left.key == 30 and t.root.right.left.key == 60


def test_contains():
    """contains finds stored keys and rejects others"""
    t = lesson_tree()
    assert all(t.contains(k) for k in (50, 20, 65, 80))
    assert not any(t.contains(k) for k in (0, 58, 100))
    assert not SearchTree().contains(1)


def test_delete_leaf_and_one_child():
    """deleting a leaf, then a node with one child"""
    t = lesson_tree()
    t.delete(20)
    assert t.inorder() == [30, 40, 50, 55, 60, 65, 70, 80] and t.root.left.left is None
    t.delete(30)
    assert t.root.left.key == 40


def test_delete_two_children_uses_successor():
    """deleting 70 moves its successor 80 up; deleting the root 50 moves 55 up"""
    t = lesson_tree()
    t.delete(70)
    assert t.root.right.key == 80 and t.inorder() == [20, 30, 40, 50, 55, 60, 65, 80]
    t.delete(50)
    assert t.root.key == 55 and t.inorder() == [20, 30, 40, 55, 60, 65, 80]


def test_delete_missing_key_and_emptying():
    """deleting a missing key does nothing; deleting every key leaves an empty tree"""
    t = lesson_tree()
    t.delete(58)
    assert t.inorder() == [20, 30, 40, 50, 55, 60, 65, 70, 80]
    for k in (50, 30, 70, 20, 40, 60, 80, 55, 65):
        t.delete(k)
    assert t.root is None and t.inorder() == []


def test_random_operations():
    """3,000 random inserts, deletes and searches agree with a plain set"""
    rng = random.Random(5)
    t, reference = SearchTree(), set()
    for _ in range(3_000):
        key = rng.randrange(400)
        op = rng.choice(("insert", "insert", "delete", "contains"))
        if op == "insert":
            t.insert(key)
            reference.add(key)
        elif op == "delete":
            t.delete(key)
            reference.discard(key)
        else:
            assert t.contains(key) == (key in reference), f"contains({key})"
    assert t.inorder() == sorted(reference)

JavaScript · Starter code · search_tree.mjs

export class Node {
  constructor(key) {
    this.key = key;
    this.left = null;
    this.right = null;
  }
}

/** A binary search tree of distinct keys. */
export class SearchTree {
  constructor() {
    this.root = null;
  }

  insert(key) {
    throw new Error('write insert');
  }

  contains(key) {
    throw new Error('write contains');
  }

  delete(key) {
    throw new Error('write delete');
  }

  inorder() {
    throw new Error('write inorder');
  }
}
The sample tests · search_tree.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { SearchTree } from './search_tree.mjs';

function lessonTree() {
  const t = new SearchTree();
  for (const k of [50, 30, 70, 20, 40, 60, 80, 55, 65]) t.insert(k);
  return t;
}

test('inorder lists the keys in increasing order, and a repeated insert changes nothing', () => {
  const t = lessonTree();
  t.insert(40);
  assert.deepEqual(t.inorder(), [20, 30, 40, 50, 55, 60, 65, 70, 80]);
  assert.ok(t.root.key === 50 && t.root.left.key === 30 && t.root.right.left.key === 60);
});

test('contains finds stored keys and rejects others', () => {
  const t = lessonTree();
  assert.ok([50, 20, 65, 80].every((k) => t.contains(k)));
  assert.ok(![0, 58, 100].some((k) => t.contains(k)));
  assert.equal(new SearchTree().contains(1), false);
});

test('deleting a leaf, then a node with one child', () => {
  const t = lessonTree();
  t.delete(20);
  assert.deepEqual(t.inorder(), [30, 40, 50, 55, 60, 65, 70, 80]);
  assert.equal(t.root.left.left, null);
  t.delete(30);
  assert.equal(t.root.left.key, 40);
});

test('deleting 70 moves its successor 80 up; deleting the root 50 moves 55 up', () => {
  const t = lessonTree();
  t.delete(70);
  assert.equal(t.root.right.key, 80);
  assert.deepEqual(t.inorder(), [20, 30, 40, 50, 55, 60, 65, 80]);
  t.delete(50);
  assert.equal(t.root.key, 55);
  assert.deepEqual(t.inorder(), [20, 30, 40, 55, 60, 65, 80]);
});

test('deleting a missing key does nothing; deleting every key leaves an empty tree', () => {
  const t = lessonTree();
  t.delete(58);
  assert.deepEqual(t.inorder(), [20, 30, 40, 50, 55, 60, 65, 70, 80]);
  for (const k of [50, 30, 70, 20, 40, 60, 80, 55, 65]) t.delete(k);
  assert.equal(t.root, null);
  assert.deepEqual(t.inorder(), []);
});

test('3,000 random inserts, deletes and searches agree with a plain set', () => {
  let s = 5;
  const next = (m) => { s = (s * 1103515245 + 12345) % 2147483648; return s % m; };
  const t = new SearchTree();
  const reference = new Set();
  const ops = ['insert', 'insert', 'delete', 'contains'];
  for (let i = 0; i < 3000; i++) {
    const key = next(400);
    const op = ops[next(4)];
    if (op === 'insert') { t.insert(key); reference.add(key); }
    else if (op === 'delete') { t.delete(key); reference.delete(key); }
    else assert.equal(t.contains(key), reference.has(key), `contains(${key})`);
  }
  assert.deepEqual(t.inorder(), [...reference].sort((a, b) => a - b));
});
A hint

Write delete as a helper that takes a subtree and returns the subtree after the deletion, then set self.root = self._delete(self.root, key). In the helper, walk left or right until you reach the key. With no left child, return the right child; with no right child, return the left one; with both, find the leftmost node of the right subtree, copy its key into the node, and delete that key from the right subtree.

The sample tests run on this device, in your browser (Pyodide, QuickJS): nothing is sent to mysmartcopilot.com. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

5 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 5 In the lesson's tree, 50(30(20, 40), 70(60(55, 65), 80)), which keys does a search for 58 compare with?

    Choose one answer.

    Show the answer to question 1

    Answer: 50, 70, 60, 55, and then it stops at an empty place

    58 is larger than 50 (go right), smaller than 70 (go left), smaller than 60 (go left) and larger than 55 (go right), where there is no child. The recorded run lists exactly [50, 70, 60, 55], and that empty place is where an insert of 58 attaches it.

  2. Question 2 of 5 4,096 distinct keys are inserted in increasing order into an empty binary search tree. What is its height?

    Type a number.

    Show the answer to question 2

    Answer: 4095

    Each new key is larger than all before it, so it becomes the right child of the previous one: the tree is a path, and its height is n − 1 = 4,095. The run measured the same, against 23 for the same keys in random order.

  3. Question 3 of 5 Which key replaces 50 when 50, a node with two children, is deleted with the successor rule?

    Choose one answer.

    Show the answer to question 3

    Answer: The smallest key in 50's right subtree

    The inorder successor is the next key in sorted order, the leftmost key of the right subtree: 55 in the lesson's tree before 55 was deleted, 58 in the run. It is larger than everything on the left and smaller than everything else on the right, so it can take 50's place.

  4. Question 4 of 5 Why is removing the successor's old node always one of the easy cases?

    Choose one answer.

    Show the answer to question 4

    Answer: It has no left child, so it has at most one child

    The successor is the leftmost node of the right subtree, so a left child would hold an even smaller key and be the successor instead. It may still have a right child, which takes its place.

  5. Question 5 of 5 What do search, insert and delete cost in a binary search tree of height h?

    Choose one answer.

    Show the answer to question 5

    Answer: O(h), which is O(log n) when the tree is balanced and O(n) when it is a path

    Each operation walks one path from the root, so it costs at most h + 1 comparisons plus constant work. The height depends on the order of the insertions unless the tree rebalances itself.

Validating a search tree and answering ordered queries, with the classic bug reproduced Pro: opens with a Pro, Premium or Ultimate pass

The most common search-tree bug is a validator that compares each node only with its children. This part builds a tree that such a validator accepts, fixes the check with bounds and proves it is enough, measures how often the bug lets damaged trees through, and checks floor, ceiling and k-th smallest against a sorted list.

In this part:

  • The children-only check, and a tree it accepts wrongly
  • Bounds passed down the tree: the fix, and why it is enough
  • How often the bug slips through, measured on 2,000 damaged trees
  • Floor, ceiling and the k-th smallest key, checked against a sorted list

1 runnable example (Python) · about 2 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Deletion proved correct, stress-tested on 100,000 operations, and duplicate keys Pro: opens with a Pro, Premium or Ultimate pass

Deletion is where search trees break most often, because it is the one operation that moves keys. This part proves that the successor rule keeps the invariant, replays 100,000 random operations against a set while checking the invariant, and reproduces how duplicate keys stored as separate nodes get lost after a deletion.

In this part:

  • Why the successor keeps the invariant: the proof
  • 100,000 random operations against a set
  • Duplicate keys: the “equal goes left” rule broken by a deletion

2 runnable examples (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Balanced builds, the library ordered maps, and the search tree in five languages Pro: opens with a Pro, Premium or Ultimate pass

Sorted input does not have to build a path, and most languages already ship an ordered map that never does. This part builds a balanced tree from sorted keys in O(n), compares the ordered structures of five standard libraries, and runs the lesson’s tree in JavaScript, Java, C++ and Go with floor and ceiling from each library.

In this part:

  • Sorted keys built middle-first: the lowest possible height
  • What the standard libraries offer
  • When a hand-written search tree is still the right choice
  • The lesson’s tree in JavaScript, Java, C++ and Go

3 runnable examples (C++, Go, Java, JavaScript, Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

  1. Fresher · Warm-up

    How do you delete a node with two children from a binary search tree, and why does its replacement never have two children itself?

    Copy the key of the node's inorder successor into it, then delete the successor's node instead. The successor is the smallest key in the right subtree: go right once, then left until there is no left child. It is the right replacement because it is the next key in sorted order, larger than every key on the left and smaller than every other key on the right, so the ordering rule still holds once it moves up. It never has two children, because a left child would hold an even smaller key of the same subtree and would be the successor instead. So removing it is one of the easy cases: it is a leaf, or its right child takes its place.

  2. Fresher to mid

    A teammate's validator checks that every node's left child is smaller and its right child larger, and it passes the team's unit tests. Construct a tree it wrongly accepts, fix the check, and explain why hand-written tests rarely catch the bug.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    User records are inserted into a plain binary search tree keyed by an auto-increment ID. After a million sign-ups, lookups take milliseconds instead of microseconds. Explain what the tree looks like, put numbers on it, and give two fixes.

    Model answer, Pro. First step and follow-ups

  4. Mid to senior

    Two binary search trees must become one: a balanced tree of 1 million keys and a balanced tree of 1,000 keys. Compare inserting the small tree's keys one by one with walking both trees in order and rebuilding, with costs, and say which you would choose.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Every key in a node’s left subtree is smaller and every key in its right subtree larger; inorder therefore lists the keys in sorted order.
  • Search and insert are one walk from the root, and insertion fills the empty place where the search ended.
  • Delete a leaf by removing it, a one-child node by lifting its child, and a two-child node by copying in its inorder successor and deleting that instead.
  • Every operation costs O(h): 4,096 random keys gave height 23, the same keys in sorted order 4,095.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.