forked from hofmannol/AlgoDatSoSe25
BinTree
This commit is contained in:
parent
ae2dfab51d
commit
f0757f30fd
@ -1,7 +1,7 @@
|
|||||||
from utils.literal import Literal
|
from utils.literal import Literal
|
||||||
from utils.memory_cell import MemoryCell
|
from utils.memory_cell import MemoryCell
|
||||||
from utils.memory_manager import MemoryManager
|
from utils.memory_manager import MemoryManager
|
||||||
from pathlib import Path
|
from utils.project_dir import get_path
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
class MemoryArray:
|
class MemoryArray:
|
||||||
@ -88,9 +88,7 @@ class MemoryArray:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def create_array_from_file(filename, limit=None):
|
def create_array_from_file(filename, limit=None):
|
||||||
"""Erzeugt ein Speicherarray aus einer Datei."""
|
"""Erzeugt ein Speicherarray aus einer Datei."""
|
||||||
this_dir = Path(__file__).resolve().parent
|
filename = get_path(filename)
|
||||||
project_dir = this_dir.parent
|
|
||||||
filename = project_dir / filename
|
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
@ -122,3 +120,7 @@ if __name__ == "__main__":
|
|||||||
s += cell
|
s += cell
|
||||||
print(s)
|
print(s)
|
||||||
print(f"Anzahl der Additionen: {MemoryManager.count_adds()}")
|
print(f"Anzahl der Additionen: {MemoryManager.count_adds()}")
|
||||||
|
|
||||||
|
a = MemoryArray.create_array_from_file("data/seq0.txt")
|
||||||
|
print(a)
|
||||||
|
|
||||||
|
13
utils/project_dir.py
Normal file
13
utils/project_dir.py
Normal file
@ -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())
|
202
vorlesung/05_binaere_baeume/bin_tree.py
Normal file
202
vorlesung/05_binaere_baeume/bin_tree.py
Normal file
@ -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)
|
24
vorlesung/05_binaere_baeume/bin_tree_node.py
Normal file
24
vorlesung/05_binaere_baeume/bin_tree_node.py
Normal file
@ -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"
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user