class TreeNode: """ Node of binary tree. Attributes: value (int): Value stored in the node. left (TreeNode): Left child. right (TreeNode): Right child. """ def __init__(self, value: int): self.value = value self.left = None self.right = None class BinarySearchTree: """ Binary Search Tree. Attributes: root (TreeNode): The root node of the tree. """ def __init__(self): self.root = None def insert(self, value: int): """ Insert value to the binary search tree. Args value (int): Value to insert """ if self.root is None: self.root = TreeNode(value) else: self._insert_recursive(self.root, value) def _insert_recursive(self, node: TreeNode, value: int): """Helper function for insert.""" if value < node.value: if node.left is None: node.left = TreeNode(value) else: self._insert_recursive(node.left, value) else: if node.right is None: node.right = TreeNode(value) else: self._insert_recursive(node.right, value) def load_from_file(self, filepath: str): """ Insert values from the file (row by row). The file should contain one value at each row. """ with open(filepath, 'r') as file: for line in file: self.insert(int(line.strip())) def load(self, values: list[int]): """ Insert values to the tree, in given order. """ for v in values: self.insert(v) def print_tree(self): """ Nicely print tree to standard output. """ self._print_tree_recursive(self.root, 0) def _print_tree_recursive(self, node: TreeNode, level: int): """ Helper function for print_tree. Args node (TreeNode): The root of subtree to print. level (int): Level of the node in original tree. """ if node is not None: self._print_tree_recursive(node.right, level + 1) print(' ' * 4 * level + '->', node.value) self._print_tree_recursive(node.left, level + 1) def contains(self, value: int) -> int: """ Compute number of occurences of value in the tree. Args value (int): The value to look for. Returns int: Number of occurences. """ # NOTE is the function named appropriately ??? E.g. count() return self._contains_recursive(self.root, value) def _contains_recursive(self, node, value): if node is None: return 0 if node.value == value: return 1 + self._contains_recursive(node.left, value) + self._contains_recursive(node.right, value) elif value < node.value: return self._contains_recursive(node.left, value) else: return self._contains_recursive(node.right, value) def find_min(self) -> int: """ Find minimum value in the tree. Returns int: Minimum value. """ # NOTE: this implementation works only in Search Trees (where values are ordered) current = self.root while current.left is not None: current = current.left return current.value def find_max(self) -> int: """ Find maximum value in the tree. Returns int: Maximum value. """ ... def sum(self) -> int: """Calculate sum of values in the tree.""" ... def calculate_average(self) -> float: """Calculate (arithmetic) average of values in the tree.""" ... def leaves_count(self) -> int: """Compute number of leaves.""" ... def height(self) -> int: """Compute height of the tree.""" ... def get_values_of_deepest_leaves(self) -> list[int]: """ Find values of nodes (leaves) at deepest level. Returns list[int]: List of values. """ def get_level_with_most_nodes(self) -> int: """ Find most occupied level, i.e. level that contains most nodes. Returns int: Index (= depth) of that level. Root is at level 0. """ def is_symmetric(self) -> bool: """ Is the tree symmetric? (Axis symmetric along the axis going through the root vertex.) """ ... tree = BinarySearchTree() # tree.load_from_file('08/tree_data.txt') tree.load([5, 2, 7, 1, 3, 9, 10]) tree.print_tree() print("number of occurences of value 5", tree.contains(5)) print("minimum", tree.find_min()) print("maximum", tree.find_max()) print("sum", tree.sum()) print("average", tree.calculate_average()) print("height", tree.height()) print("leaves count", tree.leaves_count()) print("values of deepest leaves", tree.get_values_of_deepest_leaves()) print("most occupied level", tree.get_level_with_most_nodes())