def append_to_search_tree(array: [int], node: BinaryTreeNode): array_length = len(array) if array_length == 0: return (new_node, left_part, right_part) = split_array(array) if new_node.value < node.value: node.left = new_node else: node.right = new_node append_to_search_tree(left_part, new_node) append_to_search_tree(right_part, new_node)
def find_common_ancestor_in_binary_tree_by_parent_linking( first: BinaryTreeNode, second: BinaryTreeNode, tree_root: BinaryTreeNode) -> BinaryTreeNode: first_runner = first second_runner = second while True: if first_runner is second_runner: return first_runner tree_root.parent = first first_runner = first_runner.parent tree_root.parent = second second_runner = second_runner.parent
def _append_binary_tree_nodes_recursive(parents: [BinaryTreeNode], values: List): new_parents = [] for parent in parents: if len(values) > 0: parent.left = BinaryTreeNode(values.pop()) if len(values) > 0: parent.right = BinaryTreeNode(values.pop()) new_parents.append(parent.left) new_parents.append(parent.right) if len(values) > 0: _append_binary_tree_nodes_recursive(new_parents, values)
def _append_binary_search_tree_nodes_recursive(node: BinaryTreeNode, smaller_values: List, bigger_values: List): if node is None: return (mid, left_part, right_part) = _split_in_mid_left_right(smaller_values) node.left = None if mid is None else BinaryTreeNode(mid, node) _append_binary_search_tree_nodes_recursive(node.left, left_part, right_part) (mid, left_part, right_part) = _split_in_mid_left_right(bigger_values) node.right = None if mid is None else BinaryTreeNode(mid, node) _append_binary_search_tree_nodes_recursive(node.right, left_part, right_part)
def _insert_recursive(self, compare_node: BinaryTreeNode, new_node: BinaryTreeNode): if new_node.value <= compare_node.value: if compare_node.left is None: compare_node.left = new_node new_node.parent = compare_node else: self._insert_recursive(compare_node.left, new_node) else: if compare_node.right is None: compare_node.right = new_node new_node.parent = compare_node else: self._insert_recursive(compare_node.right, new_node) compare_node.node_count += 1
def split_array(array: [int]) -> (BinaryTreeNode, [int], [int]): array_length = len(array) mid = array.pop(array_length // 2) array_length -= 1 left_part = [] right_part = [] if array_length == 1: if array[0] < mid: left_part.append(array[0]) else: right_part.append(array[0]) else: left_part = array[:array_length // 2] right_part = array[array_length // 2:] return BinaryTreeNode(mid), left_part, right_part
def get_minimum_search_tree(array: [int]) -> TreeNodeOrNone: array_length = len(array) if array_length == 0: return None mid = array.pop(array_length // 2) new_node = BinaryTreeNode(mid) array_length -= 1 if array_length == 1: leaf = BinaryTreeNode(array[0]) new_node.left = leaf if array[0] < mid else None new_node.right = leaf if array[0] >= mid else None else: new_node.left = get_minimum_search_tree(array[:array_length // 2]) new_node.right = get_minimum_search_tree(array[array_length // 2:]) return new_node
def insert(self, value): new_node = BinaryTreeNode(value) self._insert_recursive(self.root, new_node)
def __init__(self, root_value): self.root = BinaryTreeNode(root_value)
class BinaryTree: value_length = 2 def __init__(self, root_value): self.root = BinaryTreeNode(root_value) def traverse_pre_order(self, visit: Callable[[BinaryTreeNode], None]): self._traverse_pre_order_recursive(self.root, visit) def traverse_in_order(self, visit: Callable[[BinaryTreeNode], None]): self._traverse_in_order_recursive(self.root, visit) def traverse_post_order(self, visit: Callable[[BinaryTreeNode], None]): self._traverse_post_order_recursive(self.root, visit) def check_pre_order(self, predicate: Callable[[BinaryTreeNode], bool]) -> bool: return self._check_pre_order_recursive(self.root, predicate) def find_first_post_order( self, predicate: Callable[[BinaryTreeNode], bool]) -> BinaryTreeNode: return self._find_first_post_order_recursive(self.root, predicate) def find_all_in_order( self, predicate: Callable[[BinaryTreeNode], bool]) -> [BinaryTreeNode]: found = [] self._find_all_in_order_recursive(self.root, predicate, found) return found def get_depth(self) -> int: return self._get_depth_recursive(self.root, 0) def get_depth2(self) -> int: self.root.calculate_depths() return self.root.depth def is_balanced(self) -> bool: return self.check_pre_order(BinaryTreeNode.is_balanced) def is_balanced2(self) -> bool: self.root.calculate_depths() return self.check_pre_order( lambda node: node is None or node.is_balanced_by_depth()) def is_search_tree(self) -> bool: values_sorted = self._get_values_sorted_recursive(self.root) print(values_sorted) current_max = 0 for i in values_sorted: if i < current_max: return False current_max = i return True def is_search_tree2(self) -> bool: return self._check_search_tree_range(self.root, -sys.maxsize, sys.maxsize) def print(self): depth = self.get_depth() length_small_gap = 2 length_big_gap = 4 node_count_bottom = math.pow(2, depth) total_length = node_count_bottom * BinaryTree.value_length + node_count_bottom / 2 * length_small_gap + node_count_bottom / 4 * length_big_gap depth_level_linked_lists = [] self._get_depth_level_linked_lists(self.root, depth_level_linked_lists, 1) lines = map( lambda x: self._map_depth_level_linked_list_to_print_line( x, math.floor(total_length)), depth_level_linked_lists) for line in lines: print(line) def _traverse_pre_order_recursive(self, node: BinaryTreeNode, visit: Callable[[BinaryTreeNode], None]): if node is None: return visit(node) self._traverse_pre_order_recursive(node.left, visit) self._traverse_pre_order_recursive(node.right, visit) def _traverse_in_order_recursive(self, node: BinaryTreeNode, visit: Callable[[BinaryTreeNode], None]): if node is None: return self._traverse_in_order_recursive(node.left, visit) visit(node) self._traverse_in_order_recursive(node.right, visit) def _traverse_post_order_recursive(self, node: BinaryTreeNode, visit: Callable[[BinaryTreeNode], None]): if node is None: return self._traverse_post_order_recursive(node.left, visit) self._traverse_post_order_recursive(node.right, visit) visit(node) def _check_pre_order_recursive( self, node: BinaryTreeNode, predicate: Callable[[BinaryTreeNode], bool]) -> bool: return predicate(node) and ( node is None or self._check_pre_order_recursive(node.left, predicate) and self._check_pre_order_recursive(node.right, predicate)) def _find_first_post_order_recursive( self, node: BinaryTreeNode, predicate: Callable[[BinaryTreeNode], bool]) -> BinaryTreeNode: found = None if node is None else self._find_first_post_order_recursive( node.left, predicate) if found is not None: return found found = None if node is None else self._find_first_post_order_recursive( node.right, predicate) if found is not None: return found return node if predicate(node) else None def _find_all_in_order_recursive(self, node: BinaryTreeNode, predicate: Callable[[BinaryTreeNode], bool], found: List) -> [BinaryTreeNode]: if node is None: return if predicate(node): found.append(node) self._find_all_in_order_recursive(node.left, predicate, found) self._find_all_in_order_recursive(node.right, predicate, found) def _get_depth_recursive(self, node: BinaryTreeNode, depth_index: int) -> int: if node is None: return depth_index - 1 left_value = self._get_depth_recursive(node.left, depth_index + 1) right_value = self._get_depth_recursive(node.right, depth_index + 1) return left_value if left_value >= right_value else right_value def _get_depth_level_linked_lists(self, node: BinaryTreeNode, lists: [], depth_index: int): if node is None: return if len(lists) < depth_index: lists.append(LinkedList(node)) else: lists[depth_index - 1].append(node) self._get_depth_level_linked_lists(node.left, lists, depth_index + 1) self._get_depth_level_linked_lists(node.right, lists, depth_index + 1) def _get_values_sorted_recursive(self, node: BinaryTreeNode) -> []: if node is None: return [] left_values = self._get_values_sorted_recursive(node.left) right_values = self._get_values_sorted_recursive(node.right) return [*left_values, node.value, *right_values] def _check_search_tree_range(self, node: BinaryTreeNode, left_bound: int, right_bound: int) -> bool: if node is None: return True if not left_bound <= node.value <= right_bound: return False if not self._check_search_tree_range(node.left, left_bound, node.value): return False if not self._check_search_tree_range(node.right, node.value, right_bound): return False return True @staticmethod def _map_depth_level_linked_list_to_print_line(linked_list: LinkedList, total_length: int) -> str: result = '' count = linked_list.get_count() head = linked_list.root while head is not None: result += str(head.value.value).rjust(2, ' ').center( math.floor(total_length / count), ' ') head = head.next return result
def _create_left_right_random_binary_tree_nodes(node: BinaryTreeNode): if node.left is None: node.left = BinaryTreeNode(random.randint(1, 99), node) if node.right is None: node.right = BinaryTreeNode(random.randint(1, 99), node)