Umstellen der Auswertungslogik

This commit is contained in:
Oliver Hofmann
2026-03-30 13:09:16 +02:00
parent 228273f399
commit c48b5c7e59
42 changed files with 1690 additions and 1564 deletions
+48 -43
View File
@@ -1,58 +1,63 @@
from utils.memory_manager import MemoryManager
from utils.memory_array import MemoryArray
from utils.literal import Literal
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from b_tree import BTree
from b_tree_node import BTreeNode
class MemoryManagerBTree(MemoryManager):
"""
Diese Klasse erweitert den MemoryManager, um spezifische Statistiken für B-Bäume zu speichern.
"""
@staticmethod
def count_loads():
return sum([cell.loaded_count for cell in MemoryManager().cells if isinstance(cell, BTreeNode)])
@staticmethod
def count_saves():
return sum([cell.saved_count for cell in MemoryManager().cells if isinstance(cell, BTreeNode)])
@staticmethod
def save_stats(count):
data = { "cells": MemoryManager.count_cells(),
"reads": MemoryManager.count_reads(),
"writes": MemoryManager.count_writes(),
"compares": MemoryManager.count_compares(),
"adds": MemoryManager.count_adds(),
"subs": MemoryManager.count_subs(),
"muls": MemoryManager.count_muls(),
"divs": MemoryManager.count_divs(),
"bitops": MemoryManager.count_bitops(),
"loads": MemoryManagerBTree.count_loads(),
"saves": MemoryManagerBTree.count_saves() }
MemoryManager.stats[count] = data
def count_loads(root: BTreeNode) -> int:
"""Summiert load()-Aufrufe über alle Knoten des Baums."""
if root is None:
return 0
total = root.loaded_count
for child in root.children:
if child is not None:
total += count_loads(child)
return total
def count_saves(root: BTreeNode) -> int:
"""Summiert save()-Aufrufe über alle Knoten des Baums."""
if root is None:
return 0
total = root.saved_count
for child in root.children:
if child is not None:
total += count_saves(child)
return total
def analyze_complexity(sizes):
"""
Analysiert die Komplexität
ctx = AlgoContext()
stats: dict[int, dict] = {}
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
tree = BTree(5)
random_array = MemoryArray.create_random_array(size, -100, 100)
for i in range(size-1):
tree.insert(int(random_array[Literal(i)]))
MemoryManager.reset()
tree.insert(int(random_array[Literal(size-1)]))
MemoryManagerBTree.save_stats(size)
ctx.reset()
z = Array.random(size, -100, 100, ctx)
tree = BTree(5, ctx)
for i in range(size - 1):
tree.insert(z[i])
ctx.reset()
tree.insert(z[size - 1])
stats[size] = {
"comparisons": ctx.comparisons,
"writes": ctx.writes,
"loads": count_loads(tree.root),
"saves": count_saves(tree.root),
}
# Einfaches Liniendiagramm über alle gespeicherten Metriken
import matplotlib.pyplot as plt
x = list(stats.keys())
fig, axes = plt.subplots(len(stats[x[0]]), 1, figsize=(8, 12), sharex=True)
for ax, label in zip(axes, stats[x[0]].keys()):
ax.plot(x, [stats[k][label] for k in x], label=label)
ax.set_ylabel(label)
ax.legend()
plt.xlabel("n")
plt.tight_layout()
plt.show()
MemoryManager.plot_stats(["cells", "compares", "loads", "saves"])
if __name__ == "__main__":
sizes = range(1, 1001, 2)
analyze_complexity(sizes)
analyze_complexity(sizes)
+37 -34
View File
@@ -1,23 +1,29 @@
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_array import MemoryArray
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_int import Int
from b_tree_node import BTreeNode
class BTree:
def __init__(self, m: int):
def __init__(self, m: int, ctx: AlgoContext):
self.m = m
self.root = BTreeNode(m)
self.ctx = ctx
self.root = BTreeNode(m, ctx)
def _new_node(self):
return BTreeNode(self.m, self.ctx)
def search(self, value, start: BTreeNode = None) -> BTreeNode | None:
if not start:
start = self.root
start.load()
if not isinstance(value, Int):
value = Int(value, self.ctx)
i = 0
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
while i < start.n and value > start.value[Literal(i)]:
while i < start.n and value > start.value[i]:
i += 1
if i < start.n and value == start.value[Literal(i)]:
if i < start.n and value == start.value[i]:
return start
if start.leaf:
return None
@@ -26,11 +32,11 @@ class BTree:
def split_child(self, parent: BTreeNode, i: int):
child = parent.children[i]
child.load()
h = BTreeNode(self.m)
h = self._new_node()
h.leaf = child.leaf
h.n = self.m - 1
for j in range(self.m - 1):
h.value[Literal(j)] = child.value[Literal(j + self.m)]
h.value[j] = child.value[j + self.m]
if not h.leaf:
for j in range(self.m):
h.children[j] = child.children[j + self.m]
@@ -41,18 +47,18 @@ class BTree:
h.save()
for j in range(parent.n, i, -1):
parent.children[j + 1] = parent.children[j]
parent.value[Literal(j)] = parent.value[Literal(j - 1)]
parent.value[j] = parent.value[j - 1]
parent.children[i + 1] = h
parent.value[Literal(i)] = child.value[Literal(self.m - 1)]
parent.value[i] = child.value[self.m - 1]
parent.n += 1
parent.save()
def insert(self, value):
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
if not isinstance(value, Int):
value = Int(value, self.ctx)
r = self.root
if r.n == 2 * self.m - 1:
h = BTreeNode(self.m)
h = self._new_node()
self.root = h
h.leaf = False
h.n = 0
@@ -62,44 +68,40 @@ class BTree:
else:
self.insert_in_node(r, value)
def insert_in_node(self, start: BTreeNode, value):
def insert_in_node(self, start: BTreeNode, value: Int):
start.load()
i = start.n
if start.leaf:
while i >= 1 and value < start.value[Literal(i-1)]:
start.value[Literal(i)] = start.value[Literal(i-1)]
while i >= 1 and value < start.value[i - 1]:
start.value[i] = start.value[i - 1]
i -= 1
start.value[Literal(i)].set(value)
start.value[i] = value
start.n += 1
start.save()
else:
j = 0
while j < start.n and value > start.value[Literal(j)]:
while j < start.n and value > start.value[j]:
j += 1
if start.children[j].n == 2 * self.m - 1:
self.split_child(start, j)
if value > start.value[Literal(j)]:
if value > start.value[j]:
j += 1
self.insert_in_node(start.children[j], value)
def traversal(self, callback):
def traversal_recursive(node, callback):
def _rec(node, callback):
i = 0
while i < node.n:
if not node.leaf:
traversal_recursive(node.children[i], callback)
callback(node.value[Literal(i)])
_rec(node.children[i], callback)
callback(node.value[i])
i += 1
if not node.leaf:
traversal_recursive(node.children[i], callback)
traversal_recursive(self.root, callback)
_rec(node.children[i], callback)
_rec(self.root, callback)
def walk(self):
def print_key(key):
print(key, end=" ")
self.traversal(print_key)
self.traversal(lambda key: print(key, end=" "))
def height(self, start: BTreeNode = None):
if not start:
@@ -110,8 +112,9 @@ class BTree:
if __name__ == "__main__":
a = MemoryArray.create_array_from_file("data/seq3.txt")
tree = BTree(3)
ctx = AlgoContext()
a = Array.from_file("data/seq3.txt", ctx)
tree = BTree(3, ctx)
for cell in a:
tree.insert(cell)
print(f"Height: {tree.height()}")
+16 -13
View File
@@ -1,24 +1,27 @@
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_array import MemoryArray
from utils.algo_context import AlgoContext
from utils.algo_array import Array
class BTreeNode(MemoryCell):
def __init__(self, m: int):
super().__init__()
class BTreeNode:
"""
Knoten eines B-Baums.
value – Array der Schlüssel (Kapazität: 2m-1)
n – Anzahl aktuell gespeicherter Schlüssel
leaf – True wenn Blattknoten
loaded_count / saved_count – Disk-I/O-Zähler für externe Komplexitätsanalyse
"""
def __init__(self, m: int, ctx: AlgoContext):
self.m = m
self.ctx = ctx
self.n = 0
self.leaf = True
self.value = MemoryArray(Literal(2 * m - 1))
self.value = Array([0] * (2 * m - 1), ctx)
self.children = [None] * (2 * m)
self.loaded_count = 0
self.saved_count = 0
def reset_counters(self):
super().reset_counters()
self.loaded_count = 0
self.saved_count = 0
def load(self):
self.loaded_count += 1
@@ -26,4 +29,4 @@ class BTreeNode(MemoryCell):
self.saved_count += 1
def __str__(self):
return "(" + " ".join([str(self.value[Literal(i)]) for i in range(self.n)]) + ")"
return "(" + " ".join([str(self.value[i]) for i in range(self.n)]) + ")"