Data Structures and Algorithms

Binary Search Trees

All binary search trees have the property that each node is greater than or equal to all nodes in the left subtree, and less than or equal to all nodes in the right subtree.

When we want to search, we want to retrieve some piece of information by key from a large value of information. Recall from arrays and linked lists that there is worst-case \(O(n)\) retrieval information.

In BSTs, insert is as easy to implement as search.

Implementation

Node in a binary tree:

template <typename KEY>
struct Node {
    KEY key;
    Node *left, *right;
}

Here are some traversal implementations:

void inorder(Node *x) {
    if (!x) return;
    inorder(x->left);
    print(x->key);
    inorder(x->right);
}

void preorder(Node *x) {
    if (!x) return;
    preorder(x->left);
    print(x->key);
    preorder(x->right);
}

void postorder(Node *x) {
    if (!x) return;
    postorder(x->left);
    print(x->key);
    postorder(x->right);
}

Sorting

An inorder traversal is a way to get the values in order, since they are already stored in order.

What's the complexity of this?

This gives us a recurrence relation of \(\Theta (n)\)!

Node *tree_search(Node *x, Key k) {
    while (x != nullptr && k != x->key) {
        x = (k < x->key) ? x->left : x->right;
    }

    return x;
}

Complexity of this operation is \(O(h) = O(\log n)\) for the average case. For the worst case, it is \(O(n)\) if the tree is very stick-like (all elements except for one have same value).

Insertion

This is relatively similar to search, but what happens with duplicates? You have to use (<=, >) or (<, >=).

void tree_insert(Node *&x, Key k) {
    if (x == nullptr) {
        x = new Node;
        x->key = k;
        x->left = x->right = nullptr;
    }

    else if (k < x->key)
        tree_insert(x->left, k);
    else
        tree_insert(x->right, k);
}

The complexity of this is again, \(O(h) = O(\log n)\) for the average case. For the worst case, it is \(O(n)\).

Delete

  • If the node has no children, easy. Just delete it.
  • If there's one child, then just replace the node with its child.
  • If there are two children, then it's harder.

If the node has two children, then replace the node with a "combined" tree of both. Well, all the nodes in the LHS subtree are <= all in the RHS subtree. All you do is transplant the smallest RHS node to root. Make this root's left child the LHS subtree!