diff --git a/utils/memory_array.py b/utils/memory_array.py index 239f79d..a8e033c 100644 --- a/utils/memory_array.py +++ b/utils/memory_array.py @@ -1,7 +1,7 @@ from utils.literal import Literal from utils.memory_cell import MemoryCell from utils.memory_manager import MemoryManager -from pathlib import Path +from utils.project_dir import get_path from random import randint class MemoryArray: @@ -88,9 +88,7 @@ class MemoryArray: @staticmethod def create_array_from_file(filename, limit=None): """Erzeugt ein Speicherarray aus einer Datei.""" - this_dir = Path(__file__).resolve().parent - project_dir = this_dir.parent - filename = project_dir / filename + filename = get_path(filename) with open(filename) as f: lines = f.readlines() if limit is not None: @@ -122,3 +120,7 @@ if __name__ == "__main__": s += cell print(s) print(f"Anzahl der Additionen: {MemoryManager.count_adds()}") + + a = MemoryArray.create_array_from_file("data/seq0.txt") + print(a) + diff --git a/utils/project_dir.py b/utils/project_dir.py new file mode 100644 index 0000000..8c55bff --- /dev/null +++ b/utils/project_dir.py @@ -0,0 +1,13 @@ +from pathlib import Path + +def get_path(filename) -> Path: + this_dir = Path(__file__).resolve().parent + project_dir = this_dir.parent + return project_dir / filename + +if __name__ == "__main__": + filename = get_path("data/seq0.txt") + print(filename) + print(filename.resolve()) + print(filename.is_file()) + print(filename.exists()) diff --git a/vorlesung/05_binaere_baeume/bin_tree.py b/vorlesung/05_binaere_baeume/bin_tree.py new file mode 100644 index 0000000..7e6a4d3 --- /dev/null +++ b/vorlesung/05_binaere_baeume/bin_tree.py @@ -0,0 +1,202 @@ +from bin_tree_node import BinaryTreeNode +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 + if self.root is None: + self.root = self.new_node(value) + return self.root, None + else: + current = self.root + while True: + if value < current.value: + if current.left: + current = current.left + else: + current.left = self.new_node(value) + return current.left, current + elif value >= current.value: + if current.right: + current = current.right + else: + current.right = self.new_node(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) diff --git a/vorlesung/05_binaere_baeume/bin_tree_node.py b/vorlesung/05_binaere_baeume/bin_tree_node.py new file mode 100644 index 0000000..148b6b1 --- /dev/null +++ b/vorlesung/05_binaere_baeume/bin_tree_node.py @@ -0,0 +1,24 @@ +from utils.memory_cell import MemoryCell + +class BinaryTreeNode(MemoryCell): + + def __init__(self, value): + super().__init__(value) + self.left = None + self.right = None + + def height(self): + left_height = self.left.height() if self.left else 0 + right_height = self.right.height() if self.right else 0 + return 1 + max(left_height, right_height) + + def __repr__(self): + return f"TreeNode(value={self.value}, left={self.left}, right={self.right})" + + def __str__(self): + return str(self.value) + + def gv_rep(self, row, col): + """Returns the graphviz representation of the node.""" + return f"{id(self)} [label=\"{self.value}\", pos=\"{col},{-row}!\"];\n" +