Data Structures: Binary Search Tree

A node-based binary tree data structure with properties that make it highly efficient for searching, inserting, and deleting elements.

Basic Idea

Definition

Operations

Delete

Traversal

Depth-First Search (DFS)

The root is visited after visiting the left and right subtrees, because the results should be combined. So we do the expensive operations first.

treeSum

A very easy example of traversal is to find the sum of all nodes in a tree.

def treeSum(root):
    if root is None:
        return 0
    return root.val + treeSum(root.left) + treeSum(root.right)

Recursion keeps going down until it reaches the left most node and then next the base case (left child of the leaf is None)

treeMax

def treeMax(root):
    if root is None:
        return -float('inf')
    return max(root.val, treeMax(root.left), treeMax(root.right))

treeHeight

def treeHeight(root):
    if root is None:
        return 0
    return 1 + max(treeHeight(root.left), treeHeight(root.right))

existsInTree

def existsInTree(root, target):
    if root is None:
        return False
    if root.val == target:
        return True
    return existsInTree(root.left, target) or existsInTree(root.right, target)

reverseTree

Create a mirror image of the tree.

def reverseTree(root):
    if root is None:
        return
    else:
        reverseTree(root.left)
        reverseTree(root.right)
        root.left, root.right = root.right, root.left
    return root

In-order Traversal

Pre-order Traversal

Implementation in Python

Below is a basic implementation of a Binary Search Tree node and some common operations like insert and search:

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

class BST:
    def __init__(self):
        self.root = None

    def insert(self, val):
        if not self.root:
            self.root = TreeNode(val)
            return
        
        curr = self.root
        while True:
            if val < curr.val:
                if not curr.left:
                    curr.left = TreeNode(val)
                    break
                curr = curr.left
            else:
                if not curr.right:
                    curr.right = TreeNode(val)
                    break
                curr = curr.right

    def search(self, val):
        curr = self.root
        while curr:
            if val == curr.val:
                return True
            elif val < curr.val:
                curr = curr.left
            else:
                curr = curr.right
        return False

References