There are no items in your cart
Add More
					Add More
| Item Details | Price | ||
|---|---|---|---|
A comprehensive guide to understanding and implementing Binary Search Trees in Python
January 12, 2025
"A Binary Search Tree represents a powerful data structure that combines the efficiency of binary search with the flexibility of a linked structure."
A Binary Search Tree (BST) is a special type of binary tree where each node follows specific ordering properties. The left subtree of any node contains only values less than the node's value, while the right subtree contains only values greater than the node's value. This property must be maintained throughout the entire tree.
                            • All nodes in the left subtree have values less than the current node
                            • All nodes in the right subtree have values greater than the current node
                            • Both left and right subtrees must also be binary search trees
                            • The tree structure provides an average time complexity of O(log n) for operations
                        
class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.value = key
                        class BST:
    def __init__(self):
        self.root = None
    def insert(self, root, key):
        if root is None:
            return Node(key)
        
        if key < root.value:
            root.left = self.insert(root.left, key)
        else:
            root.right = self.insert(root.right, key)
        
        return root
    def insert_value(self, key):
        if not self.root:
            self.root = Node(key)
        else:
            self.insert(self.root, key)
                        BSTs can be traversed in three main ways:
# Pre-order Traversal
def pre_order_traversal(root):
    if root:
        print(root.value, end=" ")
        pre_order_traversal(root.left)
        pre_order_traversal(root.right)
# In-order Traversal
def in_order_traversal(root):
    if root:
        in_order_traversal(root.left)
        print(root.value, end=" ")
        in_order_traversal(root.right)
# Post-order Traversal
def post_order_traversal(root):
    if root:
        post_order_traversal(root.left)
        post_order_traversal(root.right)
        print(root.value, end=" ")
                    Let's explore the complete implementation of a Binary Search Tree with insertion and deletion operations. This implementation handles all cases of deletion and provides a clean, reusable interface.
class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.value = key
class BST:
    def __init__(self):
        self.root = None
    def insert(self, value):
        """Insert a new value into the BST"""
        if not self.root:
            self.root = Node(value)
        else:
            self._insert_recursive(self.root, value)
    def _insert_recursive(self, node, value):
        """Helper method for insertion"""
        if value < node.value:
            if node.left is None:
                node.left = Node(value)
            else:
                self._insert_recursive(node.left, value)
        else:
            if node.right is None:
                node.right = Node(value)
            else:
                self._insert_recursive(node.right, value)
    def delete(self, value):
        """Delete a value from the BST"""
        self.root = self._delete_recursive(self.root, value)
    def _delete_recursive(self, node, value):
        """Helper method for deletion"""
        # Base case: if node is None, tree is empty
        if node is None:
            return node
        # Recursively find the node to delete
        if value < node.value:
            node.left = self._delete_recursive(node.left, value)
        elif value > node.value:
            node.right = self._delete_recursive(node.right, value)
        else:
            # Node found! Handle the three deletion cases
            # Case 1: Leaf node (no children)
            if node.left is None and node.right is None:
                return None
            # Case 2: Node with one child
            if node.left is None:
                return node.right
            if node.right is None:
                return node.left
            # Case 3: Node with two children
            # Find the inorder successor (smallest value in right subtree)
            successor = self._find_min(node.right)
            # Copy successor value to current node
            node.value = successor.value
            # Delete the successor
            node.right = self._delete_recursive(node.right, successor.value)
        return node
    def _find_min(self, node):
        """Helper method to find the minimum value node in a subtree"""
        current = node
        while current.left is not None:
            current = current.left
        return current
                        The delete operation handles three cases:
# Create a BST and insert values
bst = BST()
values = [50, 30, 20, 40, 70, 60, 80]
for value in values:
    bst.insert(value)
# Delete operations
bst.delete(20)  # Deleting leaf node
bst.delete(30)  # Deleting node with one child
bst.delete(70)  # Deleting node with two children
        When deleting a node from a BST, we need to handle three distinct cases:
Time Complexity:
Here's how you can use this implementation:
# Create a new BST
bst = BST()
# Insert some values
values = [50, 30, 20, 40, 70, 60, 80]
for value in values:
    bst.insert(value)
# Delete a leaf node
bst.delete(20)
# Delete a node with one child
bst.delete(30)
# Delete a node with two children
bst.delete(70)
        
    Learn how to prepare for data science interviews with real questions, no shortcuts or fake promises.
See What’s Inside