Open In App

Binary Search Tree In Python

A Binary search tree is a binary tree where the values of the left sub-tree are less than the root node and the values of the right sub-tree are greater than the value of the root node. In this article, we will discuss the binary search tree in Python.

What is a Binary Search Tree(BST)?

Binary Search Tree is a data structure used in computer science for organizing and storing data in a sorted manner. Each node in a Binary Search Tree has at most two children, a left child and a right child.

Properties of BST

Binary Search Tree

In this binary tree

Creation of Binary Search Tree (BST) in Python

Below, are the steps to create a Binary Search Tree (BST).

class Tree:
    def __init__(self,val=None):
        self.value = val
        if self.value:
            self.left = Tree()
            self.right = Tree()
        else:
            self.left = None
            self.right = None
#creating a node in the tree
t = Tree(5)

Time complexity: O(1)
Space complexity: O(1)

Basic Operations on Binary Search Tree (BST)

Below, are the some basic Operations of Binary Search Tree(BST) in Python.

Insertion in Binary Search Tree(BST) in Python

Inserting a node in a Binary search tree involves adding a new node to the tree while maintaining the binary search tree (BST) property. So we need to traverse through all the nodes till we find a leaf node and insert the node as the left or right child based on the value of that leaf node. So the three conditions that we need to check at the leaf node are listed below:

Illustrations

Let us insert 13 into the below Binary search tree


Untitled-Diagramdrawio-(1)

Binary Search Tree


  • When we call the insert method then 13 is checked with the root node which is 15 , Since 13 < 15 we need to insert 13 to the left sub tree. So we recursively call left_sub_tree.insert(13)
  • Now the left child of 15 is 10 so 13 is checked with 10 and since 13>10 we need to insert 13 to the right sub tree. So we recursively call right_sub_tree.insert(13)
  • Here, the right child of 10 is 11 so 13 is checked with 11 and since 13>11 and we need to insert 13 to the right child of 11. Again we recursively call right_sub_tree.insert(13)
  • In this recursion call, we found there is no node which means we reached till the leaf node, so we create a node and insert the data in the node

After inserting 13 , the BST looks like this :


Untitled-Diagramdrawio-(2)

Inserted 13 Node in Binary Search Tree


Insertion in Binary Search Tree (BST) in Python

class Tree:
    def __init__(self,val=None):
      
        # Initialize the Tree node with a value
        self.value = val
        
        # If the node has a value, 
        #create left and right children nodes
        if self.value:
            self.left = Tree()
            self.right = Tree()
        else:
          
            # If the node has no value, 
            #set left and right children to None
            self.left = None
            self.right = None
    
    # Check if the node is empty (has no value)
    def isempty(self):
        return (self.value == None)
    
    # Insert a new value into the tree
    def insert(self,data):
      
        # If the node is empty, insert the data here
        if self.isempty():
            self.value = data
            
            # Create left and right children 
            #for the inserted node
            self.left = Tree()
            self.right = Tree()
            print("{} is inserted successfully".format(self.value))
            
        # If data is less than current node value, 
        #insert into left subtree
        elif data < self.value:
            self.left.insert(data)
            return
          
        # If data is greater than current node value, 
        #insert into right subtree
        elif data > self.value:
            self.right.insert(data)
            
        # If data is equal to current node value, do nothing
        elif data == self.value:
            return

# Create a tree with root value 15
t = Tree(15)
# Insert some values into the tree
t.insert(10)
t.insert(18)
t.insert(4)
t.insert(11)
t.insert(16)
t.insert(20)
t.insert(13)

Output
10 is inserted successfully
18 is inserted successfully
4 is inserted successfully
11 is inserted successfully
16 is inserted successfully
20 is inserted successfully
13 is inserted successfully

Time complexity: O(log n)
Space complexity: O(n)

Searching in Binary Search Tree in Python

Searching in Binary Search Tree is very easy because we don't need to traverse all the nodes. It is based on the value of nodes,which means if the value is less than root then we search in the left sub tree or else we search in right sub tree.

Illustrations

Steps to search a value 'v' in BST:

  • The value is checked with the root node, if it is equal to the root node then it returns the value
  • If the value is less than root node then it recursively calls the search operation in the left sub tree
  • If the value is greater than root node then it recursively calls the search operation in the right sub tree


Untitled-Diagramdrawio-(3)

Binary Search Tree


  • In above example BST search for value '8' begins from the root node.
  • If the value is not equal to the current node's value, the search continues recursively on the left subtree if the value is less than the current node's value.
  • Once the value matches a node, the search terminates, returning the node containing the value.

Searching in Binary Search Tree (BST) in Python

class Tree:
    def __init__(self, val=None):
        # Initialize a tree node with a value
        self.value = val
        if self.value:
            # If a value is provided, 
            #create left and right children as empty trees
            self.left = Tree()
            self.right = Tree()
        else:
            # If no value is provided, set left and 
            #right children to None
            self.left = None
            self.right = None
    
    def isempty(self):
        # Check if the tree node is empty
        return self.value == None
    
    def isleaf(self):
        # Check if the tree node is a leaf node (both left and right children are None)
        if self.left.left == None and self.right.right == None:
            return True
        else:
            return False
    
    def insert(self, data):
        if self.isempty():
            # If the current node is empty, 
            #insert the data as its value
            self.value = data
            # Create empty left and right children
            self.left = Tree()
            self.right = Tree()
        elif self.value == data:
            # If the data already exists in the tree, return
            return
        elif data < self.value:
            # If the data is less than the current node's value, 
            #insert it into the left subtree
            self.left.insert(data)
            return
        elif data > self.value:
            # If the data is greater than the current node's value, 
            #insert it into the right subtree
            self.right.insert(data)
            return
    
    def find(self, v):
        if self.isempty():
            # If the tree is empty, the value is not found
            print("{} is not found".format(v))
            return False
        if self.value == v:
            # If the value is found at the current node, 
            #print a message and return True
            print("{} is found".format(v))
            return True
        if v < self.value:
            # If the value is less than the current node's value, 
            #search in the left subtree
            return self.left.find(v)
        else:
            # If the value is greater than the current node's value, 
            #search in the right subtree
            return self.right.find(v)
    
    def inorder(self):
        if self.isempty():
            # If the tree is empty, return an empty list
            return []
        else:
            # Return the inorder traversal of the tree (left subtree, root, right subtree)
            return self.left.inorder() + [self.value] + self.right.inorder()

# Example usage
t = Tree(20)
t.insert(15)
t.insert(25)
t.insert(8)
t.insert(16)
t.find(8)
print(t.inorder())

Output
8 is found
[8, 15, 16, 20, 25]

Time complexity: O(log n)
Space complexity: O(n)

Deletion in Binary Search Tree in Python

Deleting a node in Binary search tree involves deleting an existing node while maintaining the properties of Binary Search Tree(BST). we need to search the node which needs to be deleted and then delete it.

Case 1 : While deleting a node having both left child and right child


Untitled-Diagramdrawio-(6)

Delete node 18 in BST


Testdrawio-(1)

Case 2 : While deleting a node having either left child or right child


Untitled-Diagramdrawio-(8)

Delete 16 in BST



Untitled-Diagram-(4)

Deleted 16 in BST


Case 3 : While deleting a leaf node(a node which has no child)


Untitled-Diagramdrawio-(9)

Delete 4 in BST

Untitled-Diagram-(6)

Deleted 4 in BST

Deletion in Binary Search Tree in Python

class Tree:
    def __init__(self, val=None):
        # Initialize the Tree node with a value
        self.value = val
        # Create left and right child nodes 
        #if the value is not None
        if self.value:
            self.left = Tree()
            self.right = Tree()
        else:
            self.left = None
            self.right = None

    def isempty(self):
        # Check if the node is empty (value is None)
        return (self.value == None)

    def insert(self, data):
        # Insert a new value into the Tree
        if self.isempty():
            self.value = data
            self.left = Tree()
            self.right = Tree()
        elif self.value == data:
            return
        elif data < self.value:
            self.left.insert(data)
            return
        elif data > self.value:
            self.right.insert(data)
            return

    def isleaf(self):
        # Check if the node is a leaf node (no children)
        if self.left == None and self.right == None:
            return True
        else:
            return False

    def maxval(self):
        # Find the maximum value in the Tree
        if self.right.right == None:
            return (self.value)
        else:
            return (self.right.maxval())

    def delete(self, v):
        # Delete a value from the Tree
        if self.isempty():
            return
        if v < self.value:
            self.left.delete(v)
            return
        if v > self.value:
            self.right.delete(v)
            return
        if v == self.value:
            if self.isleaf():
                self.value = None
                self.left = None
                self.right = None
                return
            elif self.left.isempty():
                self.value = self.right.value
                self.left = self.right.left
                self.right = self.right.right
                return
            else:
                self.value = self.left.maxval()
                self.left.delete(self.left.maxval())
                return

    def inorder(self):
        # Traverse the Tree in inorder (left-root-right) 
        #and return the values
        if self.isempty():
            return ([])
        else:
            return (self.left.inorder() + [self.value] + self.right.inorder())

# Test the Tree class
t = Tree(15)
t.insert(10)
t.insert(18)
t.insert(4)
t.insert(11)
t.insert(16)
t.insert(20)
print("Before deleting 4: ")
print(t.inorder())
t.delete(4)
print("After deleting 4: ")
print(t.inorder())

Output
Before deleting 4: 
[4, 10, 11, 15, 16, 18, 20]
After deleting 4: 
[10, 11, 15, 16, 18, 20]

Time complexity: O(log n)
Space complexity: O(1)

Traversals in Binary Search Tree in Python

Below, are the traversals of Binary Search Tree (BST) in Python which we can perform as SImilar to Binary Tree.

Traversals in BST in Python

class Tree:
    def __init__(self, val=None):
        # Initialize the node with a value and left and right subtrees
        self.value = val
        if self.value:
            self.left = Tree()
            self.right = Tree()
        else:
            self.left = None
            self.right = None
    
    def isempty(self):
        # Check if the tree is empty
        return self.value is None
    
    def insert(self, data):
        # Insert a value into the tree
        if self.isempty():
            self.value = data
            self.left = Tree()
            self.right = Tree()
        elif self.value == data:
            return
        elif data < self.value:
            self.left.insert(data)
        elif data > self.value:
            self.right.insert(data)
    
    def isleaf(self):
        # Check if the node is a leaf node
        return self.left is None and self.right is None
    
    def inorder(self):
        # Perform inorder traversal
        if self.isempty():
            return []
        else:
            return self.left.inorder() + [self.value] + self.right.inorder()

# Example usage
t = Tree(10)
t.insert(8)
t.insert(6)
t.insert(12)

print("Inorder Traversal : ")
print(t.inorder())

Output
Inorder Traversal : 
[6, 8, 10, 12]

Time complexity: O(log n)
Space complexity: O(n)

Applications of BST:

Advantages:

Disadvantages:


Article Tags :