Exemple #1
0
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)
Exemple #2
0
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
Exemple #3
0
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)
Exemple #4
0
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)
Exemple #5
0
 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
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
 def insert(self, value):
     new_node = BinaryTreeNode(value)
     self._insert_recursive(self.root, new_node)
Exemple #9
0
 def __init__(self, root_value):
     self.root = BinaryTreeNode(root_value)
Exemple #10
0
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
Exemple #11
0
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)