Binary Search Tree
A detailed yet simple explanation of the Binary Search Tree (BST) data structure.
What is a Binary Search Tree?
A Binary Search Tree (BST) is a special type of Binary Tree where the nodes are arranged in a specific order:
- The left child of a node contains values smaller than the node’s value.
- The right child of a node contains values greater than the node’s value.
This ordering property allows for efficient searching, insertion, and deletion operations. It is like a "sorted" Binary Tree, making it easy to search for values by comparing each node’s value and moving left or right based on whether the target value is smaller or larger.
How a Binary Search Tree Works
The key to understanding a Binary Search Tree is the ordering rule:
- At each node, I compare the target value with the node’s value.
- If the target is smaller, I move to the left child.
- If the target is larger, I move to the right child.
This continues recursively until I find the target value or reach a leaf node (a node with no children). If the value is not found, I know it doesn’t exist in the tree.
Here’s an example of a simple Binary Search Tree:
- The root node is 10.
- 5 is less than 10, so it goes to the left.
- 15 is greater than 10, so it goes to the right.
- The same comparison applies recursively for each node.
Operations on a Binary Search Tree
Here are the key operations and their time complexities in a Binary Search Tree:
-
Insertion: Add a new node while maintaining BST property
- Average Case:
O(log n)
for balanced trees - Worst Case:
O(n)
for skewed trees
- Average Case:
-
Searching: Find a specific value
- Average Case:
O(log n)
for balanced trees - Worst Case:
O(n)
for skewed trees
- Average Case:
-
Deletion: Remove a node while maintaining BST property
- Average Case:
O(log n)
for balanced trees - Worst Case:
O(n)
for skewed trees
- Average Case:
-
Traversal: Visit all nodes in specific order
- In-order, Pre-order, Post-order:
O(n)
- In-order, Pre-order, Post-order:
-
Finding Minimum/Maximum:
- Time Complexity:
O(h)
where h is height - Best Case (balanced):
O(log n)
- Worst Case (skewed):
O(n)
- Time Complexity:
-
Finding Height: Calculate number of levels
- Time Complexity:
O(n)
- Space Complexity:
O(h)
for recursive approach
- Time Complexity:
Note: The efficiency of BST operations heavily depends on the tree's balance. A balanced BST performs significantly better than a skewed one.
Insertion in a Binary Search Tree
When inserting a node, I follow these steps:
- Start at the root and compare the value to be inserted with the current node.
- If the value is smaller, move left; if larger, move right.
- Repeat this process recursively until I find an empty spot (null) where the new node can be inserted.
Deletion in a Binary Search Tree
When deleting a node, there are three possible cases:
- Node has no children: Simply remove the node.
- Node has one child: Replace the node with its child.
- Node has two children: Find the in-order successor (the smallest value node in the right subtree) or in-order predecessor (the largest value node in the left subtree), replace the node with that value, and then delete the successor or predecessor.
Code Examples
Let’s look at how I can implement basic operations like insertion and in-order traversal in C++, Python, and Java.
class Node:
def __init__(self, value):
self.data = value
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = None
# Insert a node into the binary search tree
def insert(self, value):
if self.root is None:
self.root = Node(value)
else:
self._insert(self.root, value)
# Helper function to insert a node recursively
def _insert(self, root, value):
if value < root.data:
if root.left is None:
root.left = Node(value)
else:
self._insert(root.left, value)
else:
if root.right is None:
root.right = Node(value)
else:
self._insert(root.right, value)
# In-order traversal of the tree
def in_order(self):
self._in_order(self.root)
def _in_order(self, root):
if root:
self._in_order(root.left)
print(root.data, end=" ")
self._in_order(root.right)
# Example usage
tree = BinarySearchTree()
tree.insert(10)
tree.insert(5)
tree.insert(15)
tree.insert(3)
tree.insert(7)
print("In-order traversal: ", end="")
tree.in_order() # Should print 3 5 7 10 15
print()