Skip to content

Binary Search Tree

BinarySearchTree (BinaryTree)

A binary search tree is a binary tree whose left child of each node contain an item less in value than itself, and the right child an item higher in value than itself. An in-order traversal of the binary search tree results to items arranged in ascending order.

Instantiate a binary search tree object

>>> tree = BinarySearchTree()

Insert an item to the tree

>>> tree.insert(5, 500)
>>> tree.insert(4, 400)
>>> tree.insert(6, 600)
>>> tree.insert(10, 1000)

Check if a tree is empty

>>> tree.is_empty()
False
>>> BinarySearchTree().is_empty()
True

Get root position

>>> root = tree.get_root()

Get item corresponding to a certain position

>>> root.get_data()
(5, 500)

Check if a position is owned by some tree

>>> root.is_owned_by(tree)
True
>>> root.is_owned_by(BinarySearchTree())
False

Get children of some position

>>> children = tree.get_children(root)
>>> [i.get_data() for i in children]
[(4, 400), (6, 600)]

Get left child of some position

>>> left_child = tree.get_left_child(root)
>>> left_child.get_data()
(4, 400)

Get right child of some position

>>> right_child = tree.get_right_child(root)
>>> right_child.get_data()
(6, 600)

Delete an item from the tree

>>> position_to_delete = tree.get_right_child(right_child)
>>> tree.delete(position_to_delete)

Check if a position contains the root

>>> tree.is_root(root)
True
>>> tree.is_root(left_child)
False

Check if a position contains a leaf node

>>> tree.is_leaf(left_child)
True
>>> tree.is_leaf(root)
False

Get parent of some position

>>> tree.get_parent(left_child).get_data()
(5, 500)
>>> tree.get_parent(root) is None
True

Get siblings of some position

>>> siblings = tree.get_siblings(left_child)
>>> [i.get_data() for i in siblings]
[(6, 600)]

Get height of some position

>>> tree.get_height_of_node(left_child)
0
>>> tree.get_height_of_node(root)
1

Get height of tree

>>> tree.get_height_of_tree()
1

Get depth of some position

>>> tree.get_depth_of_node(left_child)
1
>>> tree.get_depth_of_node(root)
0

Get depth of tree

>>> tree.get_depth_of_tree()
1

Get level of some position

>>> tree.get_level_of_node(left_child)
2
>>> tree.get_level_of_node(root)
1

Get length of tree

>>> len(tree)
3
>>> len(BinarySearchTree())
0

Get string reresentation of tree

>>> tree
5(4, 6)
>>> str(tree)
'5(4, 6)'

Get tree iterable

>>> tree_iterable = iter(tree)
>>> next(tree_iterable).get_data()
(5, 500)

Get next item of tree iterator

>>> next(tree).get_data()
(4, 400)

insert(self, key, value)

Insert a value into the tree

Parameters:

Name Type Description Default
key

unique identifier of the item to be added to the tree

required
value

item to be added to the tree

required
Source code in trees/binary_search_tree.py
def insert(self, key, value):
    super().insert(key, value)

    node = Tree._Node(key, value, children=[None, None])

    if self.is_empty():
        self._root = node
    else:
        current_node = self._root
        previous_node = current_node.parent

        while current_node is not None:
            previous_node = current_node
            left_child = current_node.children[0]
            right_child = current_node.children[1]
            if key == current_node.key:
                raise ValueError("Key already exists in tree")
            elif key > current_node.key:
                current_node = right_child
            else:
                current_node = left_child

        node.parent = previous_node
        if key > previous_node.key:
            previous_node.children[1] = node
        else:
            previous_node.children[0] = node

search(self, key)

Return the position of a key within the tree, or None if the value doesn't exist in the tree. Time complexity: O(n).

Parameters:

Name Type Description Default
key

the key to search

required

Returns:

Type Description
Optional[tree.Tree._Position]

the position of the item if it exists in the tree, else None

Source code in trees/binary_search_tree.py
def search(self, key) -> Union[BinaryTree._Position, None]:
    """Return the position of a key within the tree, or None if the value doesn't exist in the tree. Time
    complexity: O(n).

    :param key: the key to search
    :returns: the position of the item if it exists in the tree, else None
    """
    if self.is_empty():
        raise Empty("Tree is empty")

    current_node = self._root

    while current_node is not None:
        left_child = current_node.children[0]
        right_child = current_node.children[1]
        if key == current_node.key:
            break
        elif key > current_node.key:
            current_node = right_child
        else:
            current_node = left_child

    if current_node is None:
        return None
    else:
        return Tree._Position(self, current_node)