From f0757f30fd70a9040f1d38161fa0cb7ee0377017 Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Tue, 22 Apr 2025 13:03:40 +0200 Subject: [PATCH 1/2] BinTree --- utils/memory_array.py | 10 +- utils/project_dir.py | 13 ++ vorlesung/05_binaere_baeume/bin_tree.py | 202 +++++++++++++++++++ vorlesung/05_binaere_baeume/bin_tree_node.py | 24 +++ 4 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 utils/project_dir.py create mode 100644 vorlesung/05_binaere_baeume/bin_tree.py create mode 100644 vorlesung/05_binaere_baeume/bin_tree_node.py 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" + From 78d4b25bd471084c2cde3fb68a0c5540366f6cbe Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Tue, 22 Apr 2025 19:36:59 +0200 Subject: [PATCH 2/2] Renamed directories to use them as modules Literal: Allowed compare with None --- utils/literal.py | 4 ++++ vorlesung/{01_grundlagen => L01_grundlagen}/euklid.py | 0 .../bubble_game.py | 0 .../bubble_sorting.py | 0 .../insert_game.py | 0 .../insert_sorting.py | 0 .../select_game.py | 0 .../select_sorting.py | 0 .../heap_game.py | 0 .../heap_sorting.py | 0 .../quick_game.py | 0 .../quick_sorting.py | 0 .../count_sorting.py | 0 vorlesung/L05_binaere_baeume/__init__.py | 1 + .../{05_binaere_baeume => L05_binaere_baeume}/bin_search.py | 0 .../{05_binaere_baeume => L05_binaere_baeume}/bin_tree.py | 2 +- .../bin_tree_node.py | 0 vorlesung/__init__.py | 0 18 files changed, 6 insertions(+), 1 deletion(-) rename vorlesung/{01_grundlagen => L01_grundlagen}/euklid.py (100%) rename vorlesung/{02_elementares_sortieren => L02_elementares_sortieren}/bubble_game.py (100%) rename vorlesung/{02_elementares_sortieren => L02_elementares_sortieren}/bubble_sorting.py (100%) rename vorlesung/{02_elementares_sortieren => L02_elementares_sortieren}/insert_game.py (100%) rename vorlesung/{02_elementares_sortieren => L02_elementares_sortieren}/insert_sorting.py (100%) rename vorlesung/{02_elementares_sortieren => L02_elementares_sortieren}/select_game.py (100%) rename vorlesung/{02_elementares_sortieren => L02_elementares_sortieren}/select_sorting.py (100%) rename vorlesung/{03_fortgeschrittenes_sortieren => L03_fortgeschrittenes_sortieren}/heap_game.py (100%) rename vorlesung/{03_fortgeschrittenes_sortieren => L03_fortgeschrittenes_sortieren}/heap_sorting.py (100%) rename vorlesung/{03_fortgeschrittenes_sortieren => L03_fortgeschrittenes_sortieren}/quick_game.py (100%) rename vorlesung/{03_fortgeschrittenes_sortieren => L03_fortgeschrittenes_sortieren}/quick_sorting.py (100%) rename vorlesung/{04_besondere_sortierverfahren => L04_besondere_sortierverfahren}/count_sorting.py (100%) create mode 100644 vorlesung/L05_binaere_baeume/__init__.py rename vorlesung/{05_binaere_baeume => L05_binaere_baeume}/bin_search.py (100%) rename vorlesung/{05_binaere_baeume => L05_binaere_baeume}/bin_tree.py (98%) rename vorlesung/{05_binaere_baeume => L05_binaere_baeume}/bin_tree_node.py (100%) create mode 100644 vorlesung/__init__.py diff --git a/utils/literal.py b/utils/literal.py index ac41a93..c574306 100644 --- a/utils/literal.py +++ b/utils/literal.py @@ -21,6 +21,8 @@ class Literal: def __eq__(self, other): """Vergleicht den Wert mit einem anderen Wert.""" + if other is None: + return False assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" self.compare_count += 1 self.read_count += 1 @@ -29,6 +31,8 @@ class Literal: def __ne__(self, other): """Vergleicht den Wert der Speicherzelle mit einem anderen Wert.""" + if other is None: + return True assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell" self.compare_count += 1 self.read_count += 1 diff --git a/vorlesung/01_grundlagen/euklid.py b/vorlesung/L01_grundlagen/euklid.py similarity index 100% rename from vorlesung/01_grundlagen/euklid.py rename to vorlesung/L01_grundlagen/euklid.py diff --git a/vorlesung/02_elementares_sortieren/bubble_game.py b/vorlesung/L02_elementares_sortieren/bubble_game.py similarity index 100% rename from vorlesung/02_elementares_sortieren/bubble_game.py rename to vorlesung/L02_elementares_sortieren/bubble_game.py diff --git a/vorlesung/02_elementares_sortieren/bubble_sorting.py b/vorlesung/L02_elementares_sortieren/bubble_sorting.py similarity index 100% rename from vorlesung/02_elementares_sortieren/bubble_sorting.py rename to vorlesung/L02_elementares_sortieren/bubble_sorting.py diff --git a/vorlesung/02_elementares_sortieren/insert_game.py b/vorlesung/L02_elementares_sortieren/insert_game.py similarity index 100% rename from vorlesung/02_elementares_sortieren/insert_game.py rename to vorlesung/L02_elementares_sortieren/insert_game.py diff --git a/vorlesung/02_elementares_sortieren/insert_sorting.py b/vorlesung/L02_elementares_sortieren/insert_sorting.py similarity index 100% rename from vorlesung/02_elementares_sortieren/insert_sorting.py rename to vorlesung/L02_elementares_sortieren/insert_sorting.py diff --git a/vorlesung/02_elementares_sortieren/select_game.py b/vorlesung/L02_elementares_sortieren/select_game.py similarity index 100% rename from vorlesung/02_elementares_sortieren/select_game.py rename to vorlesung/L02_elementares_sortieren/select_game.py diff --git a/vorlesung/02_elementares_sortieren/select_sorting.py b/vorlesung/L02_elementares_sortieren/select_sorting.py similarity index 100% rename from vorlesung/02_elementares_sortieren/select_sorting.py rename to vorlesung/L02_elementares_sortieren/select_sorting.py diff --git a/vorlesung/03_fortgeschrittenes_sortieren/heap_game.py b/vorlesung/L03_fortgeschrittenes_sortieren/heap_game.py similarity index 100% rename from vorlesung/03_fortgeschrittenes_sortieren/heap_game.py rename to vorlesung/L03_fortgeschrittenes_sortieren/heap_game.py diff --git a/vorlesung/03_fortgeschrittenes_sortieren/heap_sorting.py b/vorlesung/L03_fortgeschrittenes_sortieren/heap_sorting.py similarity index 100% rename from vorlesung/03_fortgeschrittenes_sortieren/heap_sorting.py rename to vorlesung/L03_fortgeschrittenes_sortieren/heap_sorting.py diff --git a/vorlesung/03_fortgeschrittenes_sortieren/quick_game.py b/vorlesung/L03_fortgeschrittenes_sortieren/quick_game.py similarity index 100% rename from vorlesung/03_fortgeschrittenes_sortieren/quick_game.py rename to vorlesung/L03_fortgeschrittenes_sortieren/quick_game.py diff --git a/vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py b/vorlesung/L03_fortgeschrittenes_sortieren/quick_sorting.py similarity index 100% rename from vorlesung/03_fortgeschrittenes_sortieren/quick_sorting.py rename to vorlesung/L03_fortgeschrittenes_sortieren/quick_sorting.py diff --git a/vorlesung/04_besondere_sortierverfahren/count_sorting.py b/vorlesung/L04_besondere_sortierverfahren/count_sorting.py similarity index 100% rename from vorlesung/04_besondere_sortierverfahren/count_sorting.py rename to vorlesung/L04_besondere_sortierverfahren/count_sorting.py diff --git a/vorlesung/L05_binaere_baeume/__init__.py b/vorlesung/L05_binaere_baeume/__init__.py new file mode 100644 index 0000000..2dc50f9 --- /dev/null +++ b/vorlesung/L05_binaere_baeume/__init__.py @@ -0,0 +1 @@ +from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree diff --git a/vorlesung/05_binaere_baeume/bin_search.py b/vorlesung/L05_binaere_baeume/bin_search.py similarity index 100% rename from vorlesung/05_binaere_baeume/bin_search.py rename to vorlesung/L05_binaere_baeume/bin_search.py diff --git a/vorlesung/05_binaere_baeume/bin_tree.py b/vorlesung/L05_binaere_baeume/bin_tree.py similarity index 98% rename from vorlesung/05_binaere_baeume/bin_tree.py rename to vorlesung/L05_binaere_baeume/bin_tree.py index 7e6a4d3..a25c8f8 100644 --- a/vorlesung/05_binaere_baeume/bin_tree.py +++ b/vorlesung/L05_binaere_baeume/bin_tree.py @@ -1,4 +1,4 @@ -from bin_tree_node import BinaryTreeNode +from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode from utils.project_dir import get_path from datetime import datetime diff --git a/vorlesung/05_binaere_baeume/bin_tree_node.py b/vorlesung/L05_binaere_baeume/bin_tree_node.py similarity index 100% rename from vorlesung/05_binaere_baeume/bin_tree_node.py rename to vorlesung/L05_binaere_baeume/bin_tree_node.py diff --git a/vorlesung/__init__.py b/vorlesung/__init__.py new file mode 100644 index 0000000..e69de29