from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode from utils.memory_manager import MemoryManager from utils.memory_array import MemoryArray from utils.project_dir import get_path from datetime import datetime class BinaryTree: def __init__(self): self.root = None self.size = 0 def new_node(self, value): return BinaryTreeNode(value) def insert(self, value): self.size += 1 value = self.new_node(value) if self.root is None: self.root = value return self.root, None else: current = self.root while True: if value < current: if current.left: current = current.left else: current.left = value return current.left, current elif value >= current: if current.right: current = current.right else: current.right = value return current.right, current else: return None, None def search(self, value): current = self.root while current: if value < current.value: current = current.left elif value > current.value: current = current.right else: return current return None def delete(self, value): # Der Wert wird im Baum gesucht und der erste Treffer gelöscht # Rückgabe falls der Wert gefunden wird: # der Knoten, der den zu löschenden Knoten ersetzt und der Elternknoten des gelöschten Knotens parent = None current = self.root while current: if value < current.value: parent = current current = current.left elif value > current.value: parent = current current = current.right else: # Knoten gefunden break else: # Wert nicht gefunden return return self.delete_node(current, parent) def delete_node(self, current, parent): # Der übergebene Knoten wird # Rückgabe ist ein Tupel: # der Knoten, der den zu löschenden Knoten ersetzt und der Elternknoten des gelöschten Knotens self.size -= 1 # Fall 3: Es gibt zwei Kinder: wir suchen den Nachfolger if current.left and current.right: parent = current successor = current.right while successor.left: parent = successor successor = successor.left # Wert des Nachfolgers wird in den Knoten geschrieben, der gelöscht werden soll current.value = successor.value # Ab jetzt muss successor gelöscht werden; parent ist bereits richtig gesetzt current = successor # Ermitteln des einen Kindes (falls es eines gibt), sonst None # Das eine Kind ist der Ersatz für den Knoten, der gelöscht werden soll if current.left: child = current.left else: child = current.right # Falls es keinen Elternknoten gibt, ist der Ersatzknoten die Wurzel if not parent: self.root = child return child, None elif parent.left == current: parent.left = child return child, parent else: parent.right = child return child, parent def in_order_traversal(self, callback): def in_order_traversal_recursive(callback, current): if current is not None: in_order_traversal_recursive(callback, current.left) callback(current) in_order_traversal_recursive(callback, current.right) in_order_traversal_recursive(callback, self.root) def level_order_traversal(self, callback): if self.root is None: return queue = [(self.root, 0)] while queue: current, level = queue.pop(0) callback(current, level) if current.left is not None: queue.append((current.left, level + 1)) if current.right is not None: queue.append((current.right, level + 1)) def tree_structure_traversal(self, callback): def tree_structure_traversal_recursive(callback, current, level): nonlocal line if current: tree_structure_traversal_recursive(callback, current.left, level + 1) callback(current, level, line) line += 1 tree_structure_traversal_recursive(callback, current.right, level + 1) line = 0 tree_structure_traversal_recursive(callback, self.root, 0) def graph_traversal(self): def define_node(node, level, line): nonlocal file if node is not None: file.write(node.gv_rep(level, line)) def graph_traversal_recursive(current): nonlocal file if current is not None: if current.left: file.write(f"{id(current)} -> {id(current.left)}; \n") graph_traversal_recursive(current.left) if current.right: file.write(f"{id(current)} -> {id(current.right)}; \n") graph_traversal_recursive(current.right) timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S") filename = f"graph_{timestamp}.gv" filename = get_path(filename) with open(filename, "w") as file: file.write("digraph BST {\n") file.write("layout=neato;\n") file.write("node [shape=circle, fontname=\"Arial\"];\n") self.tree_structure_traversal(define_node) graph_traversal_recursive(self.root) file.write("}") if __name__ == "__main__": tree = BinaryTree() values = [5, 3, 7, 2, 4, 6, 5, 8] for value in values: tree.insert(value) def print_node(node, indent=0, line=None): print((indent * 3) * " ", node.value) print("In-order traversal:") tree.in_order_traversal(print_node) print("\nLevel-order traversal:") tree.level_order_traversal(print_node) print("\nTree structure traversal:") tree.tree_structure_traversal(print_node) print("\nGraph traversal:") tree.graph_traversal() print("\nDeleting 5:") tree.delete(5) print("In-order traversal after deletion:") tree.in_order_traversal(print_node) print("\nLevel-order traversal after deletion:") tree.level_order_traversal(print_node) print("\nTree structure traversal after deletion:") tree.tree_structure_traversal(print_node)