Compare commits

..

2 Commits

Author SHA1 Message Date
Oliver Hofmann
fe533e6d4a Umstellen der Auswertungslogik 2026-03-31 11:31:18 +02:00
Oliver Hofmann
1dfdff9391 Umstellen der Auswertungslogik 2026-03-31 11:30:26 +02:00
27 changed files with 231 additions and 466 deletions

157
README.md Normal file
View File

@ -0,0 +1,157 @@
# Algorithmen und Datenstrukturen SoSe 26
Dieses Repository enthält den Code zur Vorlesung. Neben den Vorlesungsbeispielen
bietet es ein kleines Framework, mit dem ihr eure eigenen Algorithmen
**automatisch auf Operationen messen** könnt ohne den Algorithmus selbst
anfassen zu müssen.
---
## Wozu das Framework?
In der Vorlesung analysieren wir Algorithmen theoretisch mit der O-Notation.
Das Framework erlaubt euch, diese Theorie **empirisch zu überprüfen**: Ihr
implementiert euren Algorithmus genauso wie in Python üblich nur dass ihr
statt `list` und `int` die Wrapper-Typen `Array` und `Int` verwendet. Das
Framework zählt dann im Hintergrund automatisch Vergleiche, Lese- und
Schreibzugriffe sowie arithmetische Operationen.
---
## Schnellstart
### 1. Kontext anlegen
```python
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_range import Range
ctx = AlgoContext()
```
`AlgoContext` ist der Zähler. Ihr legt ihn einmal an und gebt ihn an eure
Datenstrukturen weiter.
### 2. Array befüllen
```python
z = Array.random(10, -100, 100, ctx) # 10 Zufallszahlen zwischen -100 und 100
# oder:
z = Array([5, 3, 8, 1, 9, 2], ctx) # eigene Werte
```
### 3. Algorithmus schreiben
Schreibt euren Algorithmus wie gewohnt. `Range` ist ein Drop-in-Ersatz für
`range` und liefert ebenfalls `Int`-Objekte allerdings ohne Verbindung zum
Zähler. Dadurch wird **Indexarithmetik** (`j - 1`, `i + 1`) nicht mitgezählt,
während Operationen auf Array-*Inhalten* (die ja den echten `ctx` tragen) weiterhin
erfasst werden. Das entspricht der üblichen Konvention: gezählt werden nur
Operationen auf den Daten, nicht die Schleifensteuerung.
```python
def insertion_sort(z: Array, ctx: AlgoContext):
for i in Range(1, len(z)):
elem = z[i] # liest z[i] (1 Lesezugriff)
j = int(i) - 1
while j >= 0 and z[j] > elem: # vergleicht (1 Vergleich pro Schritt)
z[j + 1] = z[j] # schreibt (1 Schreibzugriff)
j -= 1
z[j + 1] = elem
```
### 4. Ausführen und Ergebnis ablesen
```python
insertion_sort(z, ctx)
print(ctx.comparisons) # Anzahl Vergleiche
print(ctx.reads) # Lesezugriffe
print(ctx.writes) # Schreibzugriffe
print(ctx.additions) # Additionen
```
Oder kompakt:
```python
print(ctx.summary())
```
### 5. Komplexität über mehrere Eingabegrößen plotten
```python
def analyze(sort_func, sizes):
ctx = AlgoContext()
for size in sizes:
ctx.reset()
z = Array.random(size, -100, 100, ctx)
sort_func(z, ctx)
ctx.save_stats(size)
ctx.plot_stats(["comparisons", "writes"])
analyze(insertion_sort, range(10, 201, 10))
```
Das öffnet ein Matplotlib-Fenster mit dem Verlauf der gezählten Operationen
über die Eingabegröße ihr seht direkt, ob euer Algorithmus z.B. quadratisch oder
linear wächst.
---
## Verfügbare Zähler
| Attribut | Was wird gezählt |
|-----------------|-------------------------------------------|
| `comparisons` | `<`, `>`, `<=`, `>=`, `==`, `!=` |
| `reads` | Lesezugriffe auf `Int`-Werte |
| `writes` | Schreibzugriffe (Zuweisung, `swap`) |
| `additions` | `+`, `+=` |
| `subtractions` | `-`, `-=` |
| `multiplications` | `*`, `*=` |
| `divisions` | `/`, `//`, `/=` |
| `bitops` | `&`, `\|`, `^`, `<<`, `>>` |
---
## Struktur des Repositories
```
utils/ Framework-Dateien (AlgoContext, Int, Array, Range)
vorlesung/ Vorlesungsbeispiele, geordnet nach Lektionsnummer
praktika/ Aufgabenstellungen der Praktika
playground/ Eure eigenen Abgaben und Experimente
data/ Beispieldatensätze
```
Die Vorlesungsbeispiele in `vorlesung/` sind vollständig mit dem Framework
instrumentiert und können als Vorlage für eigene Implementierungen dienen.
## Datenpfade
Die Demodaten in `data/` werden über `path()` aus `utils.algo_path` adressiert.
Die Funktion liefert immer den absoluten Pfad relativ zum Projektverzeichnis
unabhängig davon, aus welchem Verzeichnis ihr das Skript startet oder welche IDE
ihr verwendet:
```python
from utils.algo_path import path
z = Array.from_file(path("data/seq0.txt"), ctx)
```
## PriorityQueue
Für Graphalgorithmen (z.B. Dijkstra) steht eine fertige `PriorityQueue` bereit.
Sie basiert intern auf einem Heap das Prinzip habt ihr in der Vorlesung zu
Heap Sort kennengelernt. Als Abkürzung dürft ihr die fertige Klasse verwenden:
```python
from utils.algo_priority_queue import PriorityQueue
pq = PriorityQueue()
pq.add_or_update("A", 0) # Knoten mit Priorität (Distanz) eintragen
pq.add_or_update("B", 5)
pq.add_or_update("B", 2) # Priorität aktualisieren
node, dist = pq.pop() # liefert ("A", 0)
```

View File

@ -1,4 +1,6 @@
from utils.algo_context import AlgoContext
from utils.algo_int import Int
from utils.algo_array import Array
from utils.algo_range import irange
from utils.algo_range import Range
from utils.algo_path import path
from utils.algo_priority_queue import PriorityQueue

View File

@ -2,7 +2,7 @@ from __future__ import annotations
from random import randint
from utils.algo_context import AlgoContext, _NullContext, NULL_CTX
from utils.algo_int import Int
from utils.project_dir import get_path
from utils.algo_path import path
class Array:
@ -130,8 +130,8 @@ class Array:
limit : int | None
Optionale Obergrenze für die Anzahl eingelesener Zeilen.
"""
path = get_path(filename)
with open(path) as f:
filepath = path(filename)
with open(filepath) as f:
lines = f.readlines()
if limit is not None:
lines = lines[:limit]

View File

@ -117,7 +117,7 @@ class _NullContext:
"""
Kontext der alle Operationen stillschweigend ignoriert.
Wird intern von irange() verwendet, damit Schleifenindex-Arithmetik
Wird intern von Range() verwendet, damit Schleifenindex-Arithmetik
standardmäßig nicht mitgezählt wird.
__setattr__ ist absichtlich ein no-op: ``ctx.reads += 1`` bleibt wirkungslos.

View File

@ -212,6 +212,14 @@ class Int:
self._value //= other._value
return self
def __imod__(self, other):
other = self._wrap(other)
self._ctx.reads += 2
self._ctx.divisions += 1
self._ctx.writes += 1
self._value %= other._value
return self
# ------------------------------------------------------------------
# Bitoperationen (2 reads + 1 bitop + 1 write für in-place)
# ------------------------------------------------------------------

24
utils/algo_path.py Normal file
View File

@ -0,0 +1,24 @@
from pathlib import Path
def path(filename) -> Path:
"""Gibt den absoluten Pfad zu einer Datei im Projektverzeichnis zurück.
Funktioniert unabhängig vom Arbeitsverzeichnis und der verwendeten IDE,
da der Pfad relativ zur Position dieses Moduls berechnet wird.
Beispiel
--------
from utils.algo_path import path
z = Array.from_file(path("data/seq0.txt"), ctx)
"""
project_dir = Path(__file__).resolve().parent.parent
return project_dir / filename
if __name__ == "__main__":
filename = path("data/seq0.txt")
print(filename)
print(filename.resolve())
print(filename.is_file())
print(filename.exists())

View File

@ -35,6 +35,6 @@ if __name__ == "__main__":
pq.add_or_update('task3', float('inf'))
print(pq.pop()) # Should print ('task1', 1)
pq.add_or_update('task2', 0) # Update priority of 'task1'
pq.add_or_update('task2', 0) # Update priority of 'task2'
print(pq.pop()) # Should print ('task2', 0)
print(pq.pop()) # Should print ('task3', 3)

View File

@ -3,14 +3,14 @@ from utils.algo_context import AlgoContext, NULL_CTX
from utils.algo_int import Int
def irange(start_or_stop, stop=None, step: int = 1, ctx: AlgoContext = None):
def Range(start_or_stop, stop=None, step: int = 1, ctx: AlgoContext = None):
"""
Drop-in Ersatz für range(), der Int-Objekte zurückgibt.
Wird wie Pythons range() aufgerufen:
irange(stop)
irange(start, stop)
irange(start, stop, step)
Range(stop)
Range(start, stop)
Range(start, stop, step)
Indexarithmetik und Zählung
---------------------------
@ -20,13 +20,13 @@ def irange(start_or_stop, stop=None, step: int = 1, ctx: AlgoContext = None):
sollen in die Komplexitätsanalyse einfließen.
Mit ctx-Argument werden auch Indexoperationen gezählt:
for j in irange(n, ctx=ctx): ...
for j in Range(n, ctx=ctx): ...
Beispiel
--------
ctx = AlgoContext()
z = Array.random(10, 0, 99, ctx)
for i in irange(len(z) - 1): # i ist Int, Arithmetik nicht gezählt
for i in Range(len(z) - 1): # i ist Int, Arithmetik nicht gezählt
if z[i] > z[i + 1]: # Vergleich gezählt (z-Zellen haben ctx)
z.swap(i, i + 1)
"""
@ -38,7 +38,7 @@ def irange(start_or_stop, stop=None, step: int = 1, ctx: AlgoContext = None):
start, stop_ = int(start_or_stop), int(stop)
step = int(step)
assert step != 0, "irange: step darf nicht 0 sein"
assert step != 0, "Range: step darf nicht 0 sein"
num = start
if step > 0:

View File

@ -1,13 +0,0 @@
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())

View File

@ -1,175 +0,0 @@
import unittest
from utils.algo_context import AlgoContext
from utils.algo_int import Int
from utils.algo_array import Array
class TestArray(unittest.TestCase):
def setUp(self):
self.ctx = AlgoContext()
# ------------------------------------------------------------------
# Erzeugung
# ------------------------------------------------------------------
def test_from_list(self):
z = Array([3, 1, 4, 1, 5], self.ctx)
self.assertEqual(len(z), 5)
self.assertEqual(z[0].value, 3)
self.assertEqual(z[4].value, 5)
def test_random(self):
z = Array.random(20, 0, 99, self.ctx)
self.assertEqual(len(z), 20)
for cell in z:
self.assertGreaterEqual(cell.value, 0)
self.assertLessEqual(cell.value, 99)
def test_sorted(self):
z = Array.sorted(5, self.ctx)
values = [z[i].value for i in range(5)]
self.assertEqual(values, [0, 1, 2, 3, 4])
def test_from_file(self):
z = Array.from_file("data/seq0.txt", self.ctx)
self.assertGreater(len(z), 0)
def test_random_uses_no_write_counts(self):
"""Fabrikmethoden sollen keine Schreibzugriffe verzeichnen."""
z = Array.random(10, 0, 9, self.ctx)
self.assertEqual(self.ctx.writes, 0)
# ------------------------------------------------------------------
# Zugriff
# ------------------------------------------------------------------
def test_getitem_returns_int_cell(self):
z = Array([10, 20], self.ctx)
cell = z[0]
self.assertIsInstance(cell, Int)
self.assertEqual(cell.value, 10)
def test_getitem_with_int_index(self):
z = Array([10, 20, 30], self.ctx)
i = Int(2, self.ctx)
self.assertEqual(z[i].value, 30)
def test_getitem_no_read_count(self):
"""Array-Zugriff allein soll keinen read-Zähler erhöhen."""
z = Array([5, 6, 7], self.ctx)
_ = z[0]
self.assertEqual(self.ctx.reads, 0)
def test_setitem_plain_int(self):
z = Array([1, 2, 3], self.ctx)
z[0] = 99
self.assertEqual(z[0].value, 99)
self.assertEqual(self.ctx.writes, 1)
self.assertEqual(self.ctx.reads, 0)
def test_setitem_int_object(self):
z = Array([1, 2, 3], self.ctx)
v = Int(42, self.ctx)
z[1] = v
self.assertEqual(z[1].value, 42)
self.assertEqual(self.ctx.writes, 1)
self.assertEqual(self.ctx.reads, 1)
def test_setitem_cell_to_cell(self):
"""z[i] = z[j] kopiert den Wert (keine Alias-Referenz)."""
z = Array([10, 20], self.ctx)
z[0] = z[1]
self.assertEqual(z[0].value, 20)
# Wert ändern z[1] darf sich nicht mitändern
z[0] = 99
self.assertEqual(z[1].value, 20)
# ------------------------------------------------------------------
# Swap
# ------------------------------------------------------------------
def test_swap_exchanges_values(self):
z = Array([1, 2, 3, 4, 5], self.ctx)
z.swap(0, 4)
self.assertEqual(z[0].value, 5)
self.assertEqual(z[4].value, 1)
def test_swap_counts_reads_and_writes(self):
z = Array([1, 2], self.ctx)
z.swap(0, 1)
self.assertEqual(self.ctx.reads, 2)
self.assertEqual(self.ctx.writes, 2)
def test_swap_with_int_indices(self):
z = Array([10, 20, 30], self.ctx)
i = Int(0, self.ctx)
j = Int(2, self.ctx)
z.swap(i, j)
self.assertEqual(z[0].value, 30)
self.assertEqual(z[2].value, 10)
# ------------------------------------------------------------------
# Vergleich über Array-Zellen (zählt beim Int, nicht beim Array)
# ------------------------------------------------------------------
def test_cell_comparison_counts_in_ctx(self):
z = Array([5, 3], self.ctx)
result = z[0] > z[1]
self.assertTrue(result)
self.assertEqual(self.ctx.comparisons, 1)
self.assertEqual(self.ctx.reads, 2)
# ------------------------------------------------------------------
# Iteration
# ------------------------------------------------------------------
def test_iteration(self):
z = Array([1, 2, 3], self.ctx)
values = [c.value for c in z]
self.assertEqual(values, [1, 2, 3])
# ------------------------------------------------------------------
# Länge
# ------------------------------------------------------------------
def test_len(self):
z = Array([1, 2, 3, 4], self.ctx)
self.assertEqual(len(z), 4)
def test_length_returns_int(self):
z = Array([1, 2, 3], self.ctx)
n = z.length()
self.assertIsInstance(n, Int)
self.assertEqual(n.value, 3)
class TestArrayIntegration(unittest.TestCase):
"""Bubble Sort als Integrationstest für das gesamte Framework."""
def test_bubble_sort_produces_correct_result(self):
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
'../vorlesung/L02_elementares_sortieren'))
from bubble_sorting import bubble_sort
ctx = AlgoContext()
z = Array([5, 3, 1, 4, 2], ctx)
bubble_sort(z, ctx)
values = [z[i].value for i in range(len(z))]
self.assertEqual(values, [1, 2, 3, 4, 5])
def test_bubble_sort_counts_comparisons(self):
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
'../vorlesung/L02_elementares_sortieren'))
from bubble_sorting import bubble_sort
ctx = AlgoContext()
z = Array([5, 4, 3, 2, 1], ctx) # worst case
bubble_sort(z, ctx)
# n=5: maximal n*(n-1)/2 = 10 Vergleiche
self.assertGreater(ctx.comparisons, 0)
self.assertLessEqual(ctx.comparisons, 10)
if __name__ == "__main__":
unittest.main()

View File

@ -1,193 +0,0 @@
import unittest
from utils.algo_context import AlgoContext
from utils.algo_int import Int
class TestInt(unittest.TestCase):
def setUp(self):
self.ctx = AlgoContext()
def _int(self, v):
return Int(v, self.ctx)
# ------------------------------------------------------------------
# Vergleiche
# ------------------------------------------------------------------
def test_comparison_counts_reads_and_compare(self):
a, b = self._int(5), self._int(3)
result = a > b
self.assertTrue(result)
self.assertEqual(self.ctx.comparisons, 1)
self.assertEqual(self.ctx.reads, 2)
def test_all_comparison_operators(self):
a, b = self._int(4), self._int(4)
self.assertTrue(a == b)
self.assertFalse(a != b)
self.assertTrue(a <= b)
self.assertTrue(a >= b)
self.assertFalse(a < b)
self.assertFalse(a > b)
self.assertEqual(self.ctx.comparisons, 6)
self.assertEqual(self.ctx.reads, 12)
def test_comparison_with_plain_int(self):
a = self._int(5)
result = a > 3 # 3 wird auto-gewrappt, kein extra Zähler
self.assertTrue(result)
self.assertEqual(self.ctx.comparisons, 1)
self.assertEqual(self.ctx.reads, 2)
def test_eq_with_none_returns_false(self):
a = self._int(1)
self.assertFalse(a == None) # noqa: E711
self.assertEqual(self.ctx.comparisons, 0) # keine Zählung
# ------------------------------------------------------------------
# Arithmetik (binär)
# ------------------------------------------------------------------
def test_addition_returns_new_int(self):
a, b = self._int(3), self._int(4)
c = a + b
self.assertIsInstance(c, Int)
self.assertEqual(c.value, 7)
self.assertEqual(self.ctx.additions, 1)
self.assertEqual(self.ctx.reads, 2)
self.assertEqual(self.ctx.writes, 0)
def test_subtraction(self):
a, b = self._int(10), self._int(4)
c = a - b
self.assertEqual(c.value, 6)
self.assertEqual(self.ctx.subtractions, 1)
def test_multiplication(self):
a, b = self._int(3), self._int(4)
c = a * b
self.assertEqual(c.value, 12)
self.assertEqual(self.ctx.multiplications, 1)
def test_floordiv(self):
a, b = self._int(10), self._int(3)
c = a // b
self.assertEqual(c.value, 3)
self.assertEqual(self.ctx.divisions, 1)
def test_mod(self):
a, b = self._int(10), self._int(3)
c = a % b
self.assertEqual(c.value, 1)
self.assertEqual(self.ctx.divisions, 1)
def test_arithmetic_with_plain_int(self):
a = self._int(5)
c = a + 3
self.assertEqual(c.value, 8)
self.assertEqual(self.ctx.additions, 1)
def test_result_shares_context(self):
a = self._int(5)
b = self._int(3)
c = a + b # c hat denselben ctx
_ = c > self._int(0) # Vergleich auf c zählt im selben ctx
self.assertEqual(self.ctx.comparisons, 1)
# ------------------------------------------------------------------
# Augmented assignment
# ------------------------------------------------------------------
def test_iadd_counts_read_add_write(self):
a, b = self._int(5), self._int(3)
a += b
self.assertEqual(a.value, 8)
self.assertEqual(self.ctx.reads, 2)
self.assertEqual(self.ctx.additions, 1)
self.assertEqual(self.ctx.writes, 1)
def test_isub(self):
a, b = self._int(10), self._int(4)
a -= b
self.assertEqual(a.value, 6)
self.assertEqual(self.ctx.subtractions, 1)
self.assertEqual(self.ctx.writes, 1)
def test_imul(self):
a, b = self._int(3), self._int(4)
a *= b
self.assertEqual(a.value, 12)
self.assertEqual(self.ctx.multiplications, 1)
self.assertEqual(self.ctx.writes, 1)
def test_iadd_with_plain_int(self):
a = self._int(5)
a += 1
self.assertEqual(a.value, 6)
self.assertEqual(self.ctx.writes, 1)
# ------------------------------------------------------------------
# set()
# ------------------------------------------------------------------
def test_set_plain_counts_one_write(self):
a = self._int(0)
a.set(42)
self.assertEqual(a.value, 42)
self.assertEqual(self.ctx.writes, 1)
self.assertEqual(self.ctx.reads, 0)
def test_set_int_counts_write_and_read(self):
a = self._int(0)
b = self._int(7)
a.set(b)
self.assertEqual(a.value, 7)
self.assertEqual(self.ctx.writes, 1)
self.assertEqual(self.ctx.reads, 1)
# ------------------------------------------------------------------
# Typkonvertierung
# ------------------------------------------------------------------
def test_int_conversion(self):
a = self._int(5)
self.assertEqual(int(a), 5)
def test_index_usage(self):
a = self._int(2)
lst = [10, 20, 30]
self.assertEqual(lst[a], 30) # __index__
def test_hash(self):
a = self._int(5)
self.assertEqual(hash(a), hash(5))
# ------------------------------------------------------------------
# AlgoContext.reset()
# ------------------------------------------------------------------
def test_context_reset(self):
a, b = self._int(3), self._int(4)
_ = a > b
self.ctx.reset()
self.assertEqual(self.ctx.comparisons, 0)
self.assertEqual(self.ctx.reads, 0)
class TestIntNullCtx(unittest.TestCase):
"""Int ohne expliziten ctx (irange-Verwendung) keine Zählung."""
def test_arithmetic_without_ctx_produces_no_counts(self):
from utils.algo_context import NULL_CTX
a = Int(5) # uses NULL_CTX by default
b = Int(3)
_ = a + b
_ = a > b
# NULL_CTX hat feste 0-Attribute keine Ausnahme, keine Zählung
self.assertEqual(NULL_CTX.additions, 0)
self.assertEqual(NULL_CTX.comparisons, 0)
if __name__ == "__main__":
unittest.main()

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from bubble_sorting import bubble_sort_stepwise

View File

@ -1,6 +1,6 @@
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_range import irange
from utils.algo_range import Range
def bubble_sort_stepwise(z: Array, ctx: AlgoContext):
@ -11,8 +11,8 @@ def bubble_sort_stepwise(z: Array, ctx: AlgoContext):
Wird von bubble_game.py für die Visualisierung verwendet.
"""
n = len(z)
for i in irange(n - 1):
for j in irange(n - 1, i, -1):
for i in Range(n - 1):
for j in Range(n - 1, i, -1):
if z[j - 1] > z[j]:
z.swap(j - 1, j)
yield z
@ -27,7 +27,7 @@ def bubble_sort2_stepwise(z: Array, ctx: AlgoContext):
n = len(z)
while True:
swapped = False
for i in irange(n - 1):
for i in Range(n - 1):
if z[i] > z[i + 1]:
z.swap(i, i + 1)
swapped = True

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from insert_sorting import insert_sort_stepwise

View File

@ -1,7 +1,7 @@
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_int import Int
from utils.algo_range import irange
from utils.algo_range import Range
def insert_sort_stepwise(z: Array, ctx: AlgoContext):
@ -13,7 +13,7 @@ def insert_sort_stepwise(z: Array, ctx: AlgoContext):
n = len(z)
elem = Int(0, ctx) # Zwischenregister für das einzufügende Element
for i in irange(n):
for i in Range(n):
elem.set(z[i]) # 1 read + 1 write
j = Int(int(i), ctx)
while j > 0 and z[j - 1] > elem:

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from select_sorting import select_sort_stepwise

View File

@ -1,7 +1,7 @@
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_int import Int
from utils.algo_range import irange
from utils.algo_range import Range
def select_sort_stepwise(z: Array, ctx: AlgoContext):
@ -13,9 +13,9 @@ def select_sort_stepwise(z: Array, ctx: AlgoContext):
n = len(z)
cur_min = Int(0, ctx) # Index des aktuellen Minimums
for i in irange(n):
for i in Range(n):
cur_min.set(Int(int(i), ctx))
for j in irange(int(i) + 1, n):
for j in Range(int(i) + 1, n):
if z[j] < z[cur_min]:
cur_min.set(Int(int(j), ctx))
z.swap(int(i), int(cur_min))

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from heap_sorting import heap_sort_stepwise

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from quick_sorting import quick_sort_stepwise

View File

@ -1,6 +1,6 @@
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_range import irange
from utils.algo_range import Range
def count_sort(a: Array, b: Array, k: int, ctx: AlgoContext):
@ -14,15 +14,15 @@ def count_sort(a: Array, b: Array, k: int, ctx: AlgoContext):
c = Array([0] * (k + 1), ctx) # Zählarray
# Häufigkeiten zählen
for j in irange(len(a)):
for j in Range(len(a)):
c[a[j]] = c[a[j]] + 1
# Kumulierte Summen bilden
for i in irange(1, k + 1):
for i in Range(1, k + 1):
c[i] = c[i] + c[i - 1]
# Stabil in b einsortieren (rückwärts für Stabilität)
for j in irange(len(a) - 1, -1, -1):
for j in Range(len(a) - 1, -1, -1):
b[c[a[j]] - 1] = a[j]
c[a[j]] = c[a[j]] - 1

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from avl_tree import AVLTree

View File

@ -1,6 +1,6 @@
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
from utils.algo_context import AlgoContext
from utils.project_dir import get_path
from utils.algo_path import path
from datetime import datetime
import graphviz
@ -148,7 +148,7 @@ class BinaryTree:
self.tree_structure_traversal(define_node)
_rec(self.root)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
dot.render(get_path(f"{self.graph_filename()}_{timestamp}.gv"))
dot.render(path(f"{self.graph_filename()}_{timestamp}.gv"))
if __name__ == "__main__":

View File

@ -1,6 +1,6 @@
import random
import pygame
from utils.game import Game
from utils.algo_game import Game
from utils.algo_context import AlgoContext
from bin_tree import BinaryTree

View File

@ -2,7 +2,7 @@ from collections.abc import Callable
from utils.algo_context import AlgoContext
from utils.algo_array import Array
from utils.algo_int import Int
from utils.algo_range import irange
from utils.algo_range import Range
UNUSED_MARK = "UNUSED"

View File

@ -1,45 +0,0 @@
from vorlesung.L08_graphen.graph import Graph, AdjacencyMatrixGraph
from utils.project_dir import get_path
graph = AdjacencyMatrixGraph()
start = ""
end = ""
def read_file(filename: str = "data/aoc2212.txt"):
"""Read a file and return the content as a string."""
def adjust_char(char):
"""Adjust character for comparison."""
if char == 'S':
return 'a'
elif char == 'E':
return 'z'
return char
global start, end
with open(get_path(filename), "r") as file:
quest = file.read().strip().splitlines()
for row, line in enumerate(quest):
for col, char in enumerate(line):
label = f"{row},{col}"
graph.insert_vertex(label)
if char == "S":
start = label
if char == "E":
end = label
for row, line in enumerate(quest):
for col, char in enumerate(line):
for neighbor in [(row - 1, col), (row, col - 1), (row + 1, col), (row, col + 1)]:
if 0 <= neighbor[0] < len(quest) and 0 <= neighbor[1] < len(line):
if ord(adjust_char(quest[neighbor[0]][neighbor[1]])) <= ord(adjust_char(char)) + 1:
label1 = f"{row},{col}"
label2 = f"{neighbor[0]},{neighbor[1]}"
graph.connect(label1, label2)
# Lösung des Adventskalenders 2022, Tag 12
read_file("data/aoc2212test.txt")
graph.graph()
distance_map, predecessor_map = graph.bfs(start)
print(distance_map[graph.get_vertex(end)])
print(graph.path(end, predecessor_map))

View File

@ -5,8 +5,8 @@ import graphviz
import math
import heapq
from datetime import datetime
from utils.project_dir import get_path
from utils.priority_queue import PriorityQueue
from utils.algo_path import path
from utils.algo_priority_queue import PriorityQueue
from vorlesung.L09_mst.disjoint import DisjointValue
@ -155,7 +155,7 @@ class Graph:
dot.edge(str(id(self.get_vertex(edge[0]))), str(id(self.get_vertex(edge[1]))), label=str(edge[2]))
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{filename}_{timestamp}.gv"
filename = get_path(filename)
filename = path(filename)
dot.render(filename)
def dijkstra(self, start_name: str) -> tuple[dict[Vertex, float], dict[Vertex, Vertex | None]]: