2026-03-27 17:19:51 +01:00
2026-06-22 17:39:06 +02:00
2026-03-31 11:31:18 +02:00
2026-05-18 14:48:56 +02:00
2026-03-31 11:31:18 +02:00
2026-03-27 17:19:51 +01:00

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

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

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.

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

insertion_sort(z, ctx)

print(ctx.comparisons)   # Anzahl Vergleiche
print(ctx.reads)         # Lesezugriffe
print(ctx.writes)        # Schreibzugriffe
print(ctx.additions)     # Additionen

Oder kompakt:

print(ctx.summary())

5. Komplexität über mehrere Eingabegrößen plotten

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:

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:

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)
S
Description
Begleitendes Repository zur Veranstaltung "Algorithmen und Datenstrukturen"
Readme
179 KiB
Languages
Python 100%