← Startseite
⚙️

Vorlesung 12

Dijkstra fertig bauen, optimieren & Automatisierung
Vom Pseudocode zum C-Programm — schneller machen — und den Computer die Arbeit machen lassen

Fortgeschrittene Algorithmen und Programmierung
Prof. Dr. Alexandra Mikityuk
HTW Berlin

Dijkstra in C Priority Queue Automatisierung

Lernziele

  • Dijkstra als Pseudocode & Fluss verstehen — sprachunabhängig; den fertigen C-Code nur noch lesen (kein Auswendig-Tippen, kein Lab)
  • Big-O richtig lesen: was O(1), O(log n), O(n), O(n²) praktisch bedeuten — und wie stark sie sich unterscheiden
  • Optimieren lernen: den Flaschenhals finden (O(n²)) und mit der richtigen Datenstruktur (Min-Heap) auf O(E log V) drücken
  • Automatisierung (von euch gewünscht 🙌): wie echte Firmen automatisch bauen, testen & ausliefern (CI/CD) — mit Use-Cases von Netflix bis zur Fabrik

Wo wir stehen — und der Plan für heute

VL 10

Graphen, Zeiger, BFS — kürzeste Wege in Schritten.

VL 11

Dijkstra-Idee (Relax, greedy) + die Werkzeuge struct & malloc.

🎯 VL 12 — heute (letzte VL)

Drei Teile: 1) Dijkstra fertig lesen · 2) Big-O & optimieren · 3) automatisieren.

Roter Faden: Erst der Algorithmus kompakt (kein Lab, deshalb Fokus aufs Verstehen), dann der spannende Teil — warum etwas langsam ist und wie man es schneller macht (Big-O) — und zum Schluss Automatisierung, wie ihr sie euch gewünscht habt.

Erst das Bild: Dijkstra als Flussdiagramm

Pseudocode liest sich abstrakt — deshalb zuerst der Fluss. Der Kern ist eine Schleife: schnapp dir den billigsten offenen Knoten, verbessere seine Nachbarn, wiederhole.

START
alle dist = ∞,  dist[Start] = 0
Noch ein offener Knoten?
nein → liefere dist ✓ (fertig)
↓ ja
nimm offenen Knoten u mit kleinster dist
→ markiere u als fertig
für jede Kante u → v mit Gewicht w
Weg über u billiger?
dist[u] + w < dist[v]
ja → dist[v] = dist[u] + w  (RELAX)
↺ zurück zur Schleife

Was bedeuten u, v, w?

u = der Knoten, den wir gerade fertig machen (der aktuell billigste offene). Merkhilfe: u = untersucht.

v = ein Nachbar von u, den man über u erreichen kann. v = verbunden.

w = das Gewicht der Kante u→v (km, Minuten, €). w = weight / Weg-Kosten.

Und dist?

dist[x] = die bisher billigste bekannte Distanz vom Start zu Knoten x. Startet bei ∞ und wird durch RELAX immer kleiner.

In einem Satz: „Für den billigsten Knoten u schauen wir jeden Nachbarn v an — kostet der Umweg über u weniger, tragen wir den kürzeren Weg ein."

Dijkstra als Pseudocode — sprachunabhängig

Zuerst der Algorithmus ohne Sprache. Wer in Python, Java oder Rust programmiert, kann das 1:1 übersetzen — die Idee ist überall gleich.

DIJKSTRA(Graph, Start): für jeden Knoten v: dist[v] = ∞ # noch kein Weg bekannt fertig[v] = false # noch keiner abgehakt (alle offen) dist[Start] = 0 # Start kostet nichts solange es einen offenen Knoten gibt: # „offen" = fertig ist noch false u = offener Knoten mit KLEINSTER dist fertig[u] = true # u ist jetzt endgültig fertig für jede Kante (u → v) mit Gewicht w: wenn dist[u] + w < dist[v]: ← RELAX dist[v] = dist[u] + w liefere dist

u = aktueller (billigster) Knoten  ·  v = ein Nachbar von u  ·  w = Gewicht der Kante u→v  ·  dist[x] = billigste bekannte Distanz zu x  ·  fertig[x] = schon endgültig abgehakt? (Start: alle false)  ·  offen = noch nicht fertig

Zwei Zeilen sind das Herz: „nimm den Kleinsten" (greedy) und „Relax" (billiger? verbessern). Alles andere ist Buchhaltung.

Von Pseudocode zu C — was brauchen wir?

📊 dist[N]

Die billigste bekannte Distanz zu jedem Knoten. Start = 0, Rest = INF.

INF = das aus dem Pseudocode: INT_MAX = die größte int-Zahl (2 147 483 647). Als „unendlich" nutzbar, weil keine echte Distanz je so groß wird. Bedeutet: noch kein Weg bekannt.

✔️ fertig[N]

Wer ist schon endgültig „abgehakt"? 0 = offen, 1 = fertig.

🔗 adj[N]

Die Adjazenzliste aus VL 11 — pro Knoten eine Liste seiner Kanten (Ziel + Gewicht).

Knoten sind Zahlen: statt Namen (A, B, C…) nummerieren wir die Knoten 0, 1, … N-1 und nutzen die Nummer als Array-Index. start = Nummer des Startknotens (0 = A). Das ist genau die Tabelle von VL 11 — pro Knoten dist und fertig. Jetzt in einem kompakten Programm.

Das ganze Dijkstra auf einen Blick

Kein Lab zum Üben — deshalb einmal kompakt statt in Häppchen: das komplette Programm mit den drei Schritten markiert. Ihr müsst es nicht auswendig tippen, sondern lesen können.

typedef struct Kante { int ziel, gewicht; struct Kante *next; } Kante;

int dist[N], fertig[N], start = 0;
// (1) INIT: alles unbekannt (INF), Start = 0
for (int i = 0; i < N; i++) { dist[i] = INF; fertig[i] = 0; }
dist[start] = 0;

for (int schritt = 0; schritt < N; schritt++) {
    // (2) billigsten OFFENEN Knoten u waehlen
    int u = -1;
    for (int i = 0; i < N; i++) {
        if (fertig[i])      continue;   // schon abgehakt
        if (dist[i] == INF) continue;   // unerreichbar
        if (u == -1 || dist[i] < dist[u]) // erster ODER billiger?
            u = i;
    }
    if (u == -1) break;   // nichts Offenes mehr -> fertig
    fertig[u] = 1;

    // (3) RELAX: Nachbarn von u ueber die Kanten verbessern
    for (Kante *e = adj[u]; e != NULL; e = e->next)
        if (dist[u] + e->gewicht < dist[e->ziel])
            dist[e->ziel] = dist[u] + e->gewicht;
}

Die 3 Schritte

(1) Init · (2) den Kleinsten nehmen (greedy) · (3) relaxen — dann wiederholen. Exakt der Pseudocode, ~15 Zeilen.

Die Kürzel

u = billigster offener Knoten
e = Zeiger auf eine Kante von u
e->ziel = Nachbar, e->gewicht = Kosten
u=-1 = „noch keinen"; INF = ∞

Schritt (2) merken: N-mal über alle N → O(n²). Hier setzen wir gleich den Hebel an.

Es läuft — und findet clevere Umwege

Start A: das Programm gibt für jeden Knoten die kürzeste Distanz aus.

A -> A: 0
A -> B: 3      // via C, nicht direkt!
A -> C: 1
A -> D: 4
A -> E: 7

🔑 Der Aha-Moment

Nach B führt die direkte Kante A→B = 4. Aber der Umweg A→C→B = 1+2 = 3 ist billiger. Dijkstra findet das — kürzester Weg heißt nicht wenigste Kanten, sondern kleinste Summe.

Und es stimmt: exakt das Ergebnis, das wir in VL 11 von Hand in die Tabelle gerechnet haben — jetzt rechnet es das Programm für jeden Graphen automatisch. Bleibt die Frage: wie schnell?

Wozu das Ganze? Dijkstra in der echten Welt

Derselbe Algorithmus, den ihr gerade gelesen habt, läuft milliardenfach am Tag:

🧭 Navigation

Google Maps, Auto-Navi, ÖPNV-Apps: kürzeste/schnellste Route. Kanten = Straßen, Gewicht = Minuten oder km.

🌐 Netzwerke

Internet-Router bestimmen den günstigsten Weg für Datenpakete. Gewicht = Leitungskosten.

Das Protokoll OSPF = Open Shortest Path First („offener Kürzeste-Wege-zuerst") nutzt dafür direkt Dijkstra.

🎮 Spiele & Robotik

Wege-Findung für Figuren und Roboter (oft A*, eine Dijkstra-Erweiterung). Gewicht = Geländekosten.

Deshalb lohnt der zweite Teil: Bei einer Straßenkarte mit Millionen Knoten entscheidet die Laufzeit über „Route in Millisekunden" vs. „unbenutzbar". Genau darum kümmern wir uns jetzt.

Der Flaschenhals: warum O(n²)?

🐌 Das Problem

Wir machen N Runden (einen Knoten pro Runde fertig). Um den Kleinsten zu finden, läuft die for-Schleife über alle N Plätze — fertige überspringt sie mit !fertig[i], aber anschauen muss sie jeden.

N Runden × ~N Blicke = O(n²).

🔍 Und das Relaxen?

Das ist der andere Teil des Algorithmus — und der ist billig. Jeder Knoten schaut, sobald er fertig wird, einmal seine eigenen Kanten an.

Beispiel: 5 Knoten, 7 Kanten. A guckt seine Kanten an, B seine, C seine … Über alle Knoten summiert wird jede Kante genau 1× angefasst → nur 7 Relax-Checks insgesamt (nicht 5×5).

So viele Schritte wie es Kanten gibt (E = Edges) → in Big-O: O(E). Gegen die 25 Blicke der Minimum-Suche ist das winzig.

Und „fertige überspringen" rettet nicht: Selbst wenn wir nur die offenen anschauen, sind das N + (N−1) + … + 1 = N²/2 Blicke — immer noch O(n²). Das eigentliche Problem ist nicht welche Knoten wir ansehen, sondern dass wir überhaupt suchen müssen. Genau das nimmt uns gleich der Min-Heap ab: er liefert den Kleinsten ohne Suche.

Erinnerung aus VL 5: Was heißt O(…)?

Big-O hattet ihr schon in VL 5 — hier die Kurz-Auffrischung, weil wir es gleich für Dijkstra brauchen. Es beschreibt, wie die Laufzeit wächst, wenn die Eingabe größer wird — nicht die genaue Zeit in Sekunden.

📏 Die zwei Regeln

1. Konstanten weg: O(2n), O(n+100) → alles O(n). Ob 2 oder 100 Schritte pro Element ist egal — es geht ums Wachstum.

2. Nur der größte Term zählt: O(n² + n)O(n²). Bei großem n erdrückt alles andere.

🧠 In Worten

O(1) — immer gleich, egal wie groß (Array-Zugriff).

O(log n) — wächst kaum (Halbieren / Heap).

O(n) — proportional (einmal durchlaufen).

O(n²) — jeder mit jedem (verschachtelte Schleife).

Warum uns das interessiert: Big-O sagt voraus, ob ein Programm bei echten Datenmengen noch in Millisekunden läuft — oder in Stunden. Genau das trennt Dijkstras O(n²) von der Heap-Version.

Wie stark ist der Unterschied wirklich?

Angenommen, ein Schritt dauert 1 Nanosekunde. So viele Schritte braucht jede Komplexität bei wachsendem n:

n (Eingabegröße)O(log n)O(n)O(n log n)O(n²)
10~310~33100
1 000~101 000~10 0001 000 000
1 000 000~201 Mio~20 Mio1 000 000 000 000
Bei 1 Mio: Zeit20 ns1 ms20 ms~17 Minuten
Das ist der ganze Punkt: Bei 1 Mio Knoten ist O(n²)17 Minuten, O(n log n) nur 20 msfünfzigtausendmal schneller. Nicht ein bisschen — eine andere Welt. Deshalb optimieren wir.

Die Lösung: eine Priority Queue

Wir tauschen das „jedes Mal alle durchsuchen" gegen eine clevere Warteschlange, die uns den Kleinsten sofort gibt.

🐌 Bisher: Array-Scan

„Zeig mir den Kleinsten" → alle N durchsehen → O(n) pro Runde.

Neu: Priority Queue

Eine Warteschlange, die immer das kleinste Element vorne hat. „Zeig mir den Kleinsten" → sofort.

Priority Queue = Warteschlange nach Priorität statt nach Ankunft. Die übliche Umsetzung heißt Min-Heap.

Kurz erklärt: der Min-Heap

1 3 4 7 5 8 kleinster oben ↑

🌳 Die Regel

Ein Binärbaum, in dem jeder Elternknoten ≤ seine Kinder ist. Folge: der kleinste steht ganz oben.

⏱️ Das Tempo

Kleinsten ansehen: O(1). Einfügen & Kleinsten entfernen: O(log n) — nur den Baum-Pfad reparieren, nicht alles durchsuchen.

Kernidee: Statt jedes Mal alle N zu prüfen (O(n)), kostet „gib den Kleinsten" nur noch O(log n) — man repariert nur einen Baum-Pfad. Warum das genau log n ist, sehen wir auf der nächsten Folie.

Warum ist ein Baum nur log n hoch?

log n klingt abstrakt — ist aber ganz einfach: „Wie oft muss ich verdoppeln, um von 1 bis n zu kommen?" Genau das schauen wir jetzt an.

Verdopplungs-Leiter — zähle die Schritte:

1 2 4 8 16 1 Mio

Von 1 bis 1 000 000 sind es nur 20 Verdopplungenlog₂(1 000 000) ≈ 20.

🌳 Und der Baum?

Jede Ebene nach unten verdoppelt die Zahl der Knoten: 1, 2, 4, 8, … Also ist „Anzahl Ebenen" genau „Anzahl Verdopplungen" = log₂ n. Ein Baum mit 1 Mio Knoten ist darum nur ~20 Ebenen hoch — nicht 1 Mio!

🔧 Warum das den Heap schnell macht

Die zwei Heap-Aktionen: Einfügen = eine neue Zahl in den Heap legen · Entfernen = den Kleinsten herausnehmen (das „gib den Kleinsten").

Danach kann die Regel „Eltern ≤ Kinder" kurz verletzt sein — der Heap repariert sich, aber nur entlang eines Wegs von oben nach unten (eine Ebene pro Schritt). Bei nur ~log n Ebenen sind das nur ~log n Schritte. Die anderen Knoten fasst man nie an — statt alle n zu durchsuchen.

Merksatz: Die Knotenzahl wächst riesig (verdoppeln), die Höhe kaum (log n). 1000× mehr Knoten = nur ~10 Ebenen mehr. Das ist der ganze Grund, warum der Heap so schnell ist.

Dijkstra mit Priority Queue: der Gewinn

Minimum findenGesamtaufwand
Einfach (Array-Scan)O(n) pro RundeO(n²)
Mit Min-HeapO(log n) pro OperationO(E · log V)
Bei „dünnen" Graphen (wenige Kanten pro Knoten, wie Straßennetze) ist E · log V viel kleiner als — der Unterschied zwischen „geht nicht" und „Millisekunden". Genau das steckt in eurem Navi.

V = Knoten, E = Kanten. (Den Min-Heap selbst zu bauen ist ein eigenes Thema — Idee & Nutzen zählen hier.)

Wann lohnt sich Optimieren — und wann nicht?

Schneller ist nicht immer besser. Der Heap lohnt sich nicht überall:

Lohnt sich

Große Daten: Millionen Knoten (Landkarte, Netzwerk). Da entscheidet O(n²) vs. O(E·log V) über benutzbar oder nicht.

Heißer Pfad: Code, der oft läuft (jede Route-Anfrage von Millionen Nutzern).

🛑 Lohnt sich nicht

Kleine Daten: 20 Knoten? Beide Versionen fühlen sich sofort an — die einfache ist kürzer & weniger fehleranfällig.

Läuft nur selten: ein Skript einmal pro Woche muss nicht schnell sein.

„Premature optimization is the root of all evil." (D. Knuth) — Erst richtig und einfach, dann messen, und nur den echten Flaschenhals optimieren. Nicht auf Verdacht.

Optimieren — das übertragbare Rezept

Was wir bei Dijkstra gemacht haben, ist ein allgemeines Muster — für jedes Programm:

1️⃣ Messen, nicht raten

Finde heraus, wo die Zeit wirklich draufgeht (Profiler, Stoppuhr). Menschen raten fast immer falsch.

2️⃣ Den Flaschenhals angehen

Nur der teuerste Teil zählt. Bei Dijkstra: die Minimum-Suche — nicht das Relaxen.

3️⃣ Bessere Datenstruktur

Oft kommt der große Sprung nicht durch „schnelleren Code", sondern durch die richtige Struktur (Array-Scan → Min-Heap).

Die eigentliche Lektion: Der Algorithmus blieb gleich — wir haben nur eine Datenstruktur getauscht und damit O(n²)O(E·log V) gewonnen. Datenstrukturen sind der Hebel.

🤖 Teil 2: Automatisierung

Beim Entwickeln macht ihr dieselben Schritte immer wieder: kompilieren, starten, testen. Automatisierung heißt: einmal aufschreiben, der Rechner wiederholt es.

😩 Von Hand

gcc … tippen, starten, Ausgabe prüfen, Tippfehler, nochmal … bei jeder Änderung.

⚙️ Automatisiert

Ein Befehl — make oder ./build.sh — macht alles. Reproduzierbar, kein Vergessen.

🎯 Warum wichtig

Weniger Fehler, mehr Zeit fürs Denken. So arbeiten Profis (und CI-Systeme) wirklich.

Faustregel: Was ihr dreimal von Hand macht, sollte ein Skript machen.

Was lohnt sich zu automatisieren?

Nicht alles — aber drei Arten von Aufgaben schreien geradezu danach:

🔁 Wiederkehrendes

Was man immer wieder gleich macht: bauen, starten, Dateien kopieren, umbenennen. Langweilig und fehleranfällig — perfekt fürs Skript.

Prüfen & Kontrollieren

Testen, ob nach einer Änderung noch alles stimmt. Der Rechner vergisst nie einen Test — der Mensch schon.

Von selbst / regelmäßig

Dinge, die nachts, bei jeder Änderung oder bei einem Ereignis passieren sollen — ohne dass jemand dran denkt.

Faustregel: Was ihr dreimal von Hand macht, sollte ein Skript machen. Schauen wir, wie Firmen genau das im Großen tun.

Wie Firmen Software ausliefern: die Pipeline

In echten Firmen macht niemand mehr „bauen, testen, hochladen" von Hand. Jede Code-Änderung läuft automatisch durch eine Kette — die CI/CD-Pipeline.

📝 Commit
Code ändern
🔨 Build
bauen
✅ Test
automatisch prüfen
🚀 Deploy
live schalten
📊 Monitor
überwachen

CI = Continuous Integration

Jede Änderung wird sofort gebaut & getestet. Fehler fallen in Minuten auf — nicht Wochen später.

CD = Continuous Delivery

Ist alles grün, geht der Code automatisch live — ohne dass jemand von Hand etwas hochlädt.

Der Kern: Menschen schreiben Code — alles danach macht die Pipeline von selbst. Das ist Automatisierung im Großen.

CI, Delivery, Deployment — die drei Stufen

„CI/CD" sind eigentlich drei Ausbaustufen — jede automatisiert einen Schritt mehr:

Continuous Integration

Bei jedem Commit wird automatisch gebaut & getestet. Ergebnis: „Code ist gesund" ✓ oder ✗.

Continuous Delivery

Der Code ist jederzeit release-bereit. Das Live-Schalten ist nur noch ein Knopfdruck — ein Mensch gibt frei.

Continuous Deployment

Sogar die Freigabe ist automatisch: besteht alles, geht es ohne Mensch direkt live.

Der feine Unterschied: Bei ② drückt noch ein Mensch den Knopf, bei ③ nicht mehr. Netflix & Co. sind bei ③ — deshalb tausende Deploys pro Tag.

Welche Tests gibt es? Die Testpyramide

Im „Test"-Schritt der Pipeline stecken mehrere Arten von Tests — von klein & schnell bis groß & langsam:

🌐 E2E
wenige, langsam
🔗 Integration
mittel
🧩 Unit
viele, schnell

🧩 Unit-Test

Testet eine kleine Funktion isoliert. Z.B.: „Gibt relax() bei diesen Zahlen das Richtige?" Millisekunden — tausende davon.

🔗 Integration-Test

Testet, ob mehrere Teile zusammen funktionieren. Z.B.: „Lesen Graph-Loader + Dijkstra die Datei korrekt ein?"

🌐 End-to-End (E2E)

Testet das ganze System wie ein echter Nutzer. Z.B.: „Nutzer gibt Start+Ziel ein → bekommt die richtige Route."

Die Pyramide-Regel: viele schnelle Unit-Tests unten, wenige langsame E2E oben. So bleibt die CI schnell und findet Fehler trotzdem zuverlässig.

Was die CI sonst noch automatisch prüft

„Funktioniert es?" ist nur der Anfang. Moderne Pipelines prüfen bei jedem Commit auch:

Test-Artprüft …
RegressionstestKommt ein alter, schon gefixter Bug zurück? (sichert jeden gefundenen Fehler dauerhaft ab)
Smoke-TestLäuft das Programm überhaupt an? (schneller Grob-Check vor allen anderen)
Last-/Performance-TestHält es 10.000 Nutzer gleichzeitig aus? Wird es langsamer? (genau hier zählt euer Big-O-Wissen!)
Security-ScanStecken bekannte Sicherheitslücken in den benutzten Bibliotheken?
Linter / Style-CheckIst der Code sauber & einheitlich formatiert? (kein Fehler, aber Ordnung)
Erst wenn ALLES grün ist, darf der Code weiter Richtung „live". Ein einziges ✗ stoppt die Pipeline — automatisch.

So automatisieren Tech-Firmen

🔴 Netflix

Deployt tausende Male am Tag. Ein Programm („Chaos Monkey") legt absichtlich Server lahm, um automatisch zu prüfen, ob alles stabil bleibt.

🔵 Google / Amazon

Jede Änderung durchläuft Millionen automatischer Tests, bevor sie Nutzer erreicht — Deploy im Sekundentakt, rund um die Uhr.

⚙️ Auto-Skalierung

Viele Nutzer? Das System startet von selbst mehr Server; nachts fährt es sie wieder herunter. Kein Mensch dreht am Regler.

Warum das nur automatisiert geht: Tausende Deploys pro Tag könnte kein Mensch von Hand testen & ausliefern. Automation ist die Voraussetzung für diese Größe — nicht bloß Bequemlichkeit.

Automation gibt es überall — nicht nur bei IT-Firmen

🛒 E-Commerce

Preise passen sich automatisch an, ein niedriger Lagerbestand löst Nachbestellungen aus, Empfehlungen werden für jeden Nutzer berechnet.

🏦 Banken & Finanzen

Nächtliche Reports und Abrechnungen laufen von selbst; die Betrugserkennung prüft jede Zahlung in Echtzeit — automatisch.

🏭 Industrie & Fabriken

Roboter, Sensoren, Kamera-Qualitätskontrolle. Maschinen melden Wartungsbedarf selbst und sprechen miteinander — M2M (Maschine zu Maschine).

Gemeinsamer Nenner: Überall, wo etwas wiederkehrend, schnell oder rund um die Uhr passieren muss, übernimmt Software die Routine — vom Webshop bis zur Fabrikhalle.

Ein Feature geht live — in Minuten statt Wochen

So fließt heute eine kleine Änderung durch eine Firma — fast ohne Handarbeit:

  1. Eine Entwicklerin ändert Code und speichert die Version (Commit).
  2. Die Pipeline startet automatisch: sie baut das Programm und lässt alle Tests laufen.
  3. Alles grün? Der Code geht automatisch live — für Millionen Nutzer, ohne Handgriff.
  4. Monitoring beobachtet: geht etwas schief, wird automatisch die alte Version zurückgeholt.
Früher: Wochen, viele Hände, riskant.   Heute: Minuten, automatisch, sicher — weil jeder Schritt ein Skript ist statt Handarbeit.

Warum Firmen so viel automatisieren

Tempo

Neue Funktionen in Minuten statt Wochen ausliefern. Wer schneller liefert, gewinnt den Markt.

🛡️ Zuverlässigkeit

Automatische Tests fangen Fehler, bevor Nutzer sie sehen. Menschen vergessen — Skripte nicht.

📈 Skalierung

Millionen Nutzer bedienen, ohne dass die Mannschaft mitwächst. Den Massen-Kram macht der Rechner.

Und für euch: dieselbe Idee im Kleinen — „was du 3× von Hand machst, gib einem Skript" — spart Zeit und Nerven, egal ob Uni-Projekt oder Weltkonzern.

Die Werkzeuge — grob eingeordnet

Ihr müsst sie hier nicht können — nur wissen, dass es sie gibt und wofür sie da sind:

Aufgabetypische Werkzeuge
Bauen (Code → fertiges Programm)Make, Gradle, npm
Versionieren (Historie & Teamarbeit)Git (GitHub, GitLab)
Automatisch testen & ausliefern (CI/CD)GitHub Actions, GitLab CI, Jenkins
Verpacken (überall gleich lauffähig)Docker / Container
Zeitgesteuert starten (nachts, wöchentlich)cron, Scheduler
Merkt euch die Konzepte, nicht die Namen: bauen · versionieren · testen · ausliefern · planen. Die konkreten Werkzeuge wechseln — die Idee dahinter bleibt.

Faustregeln für Automatisierung

👍 Automatisiere

Was du 3× von Hand machst · Tests · Builds · alles Fehleranfällige oder Langweilige.

Lieber nicht

Einmalige Aufgaben · Dinge, die menschliches Urteil brauchen · wenn das Skript-Bauen länger dauert als die Handarbeit je kostet.

💡 Merke

Ein Skript ist auch Dokumentation: es zeigt exakt, wie etwas gebaut/getestet wird — reproduzierbar für alle im Team.

Ziel ist nicht „alles automatisieren", sondern die richtige Arbeit dem Rechner geben — damit ihr Zeit für das habt, was nur Menschen können: Probleme lösen.

Zusammenfassung — in einer Slide

  • Dijkstra = Init · den Kleinsten nehmen (greedy) · Kanten relaxen · wiederholen. Der Pseudocode zählt — die Sprache ist egal.
  • Big-O beschreibt das Wachstum: Konstanten weg, größter Term zählt. Bei 1 Mio Knoten ist O(n²) Minuten, O(n log n) Millisekunden.
  • Optimieren = messen → Flaschenhals finden (Minimum-Suche) → bessere Datenstruktur. Min-Heap: O(n²)O(E·log V).
  • log n = Baumhöhe: jede Ebene verdoppelt → nur ~20 Ebenen für 1 Mio. Reparieren läuft nur einen Pfad.
  • Automatisierung: Firmen bauen, testen & liefern automatisch aus (CI/CD-Pipeline) — Tempo, Zuverlässigkeit, Skalierung. Was ihr 3× von Hand macht, gehört ins Skript.

Was ihr jetzt könnt — ein ganzes Semester

Das war die letzte inhaltliche Vorlesung. Schaut, wie weit ihr gekommen seid:

🧩 Algorithmen

Sortieren, Suchen, Rekursion, Graphen, BFS & Dijkstra — die Bausteine echter Software.

Denken in Big-O

Ihr erkennt, warum etwas langsam ist, und wählt die passende Datenstruktur, um es zu lösen.

⚙️ Werkzeuge & Automation

struct, malloc, Zeiger — und wie Firmen mit CI/CD automatisch bauen, testen & ausliefern.

Nächste VL: Rückblick über die ganze Reihe & Klausurvorbereitung — kein neuer Stoff, dafür Übung an alten Aufgaben. Bringt eure Fragen mit!

Vielen Dank!

Erst richtig, dann schnell, dann automatisch. ⚙️

Prof. Dr. Alexandra Mikityuk

HTW Berlin · Büro Raum 308

Nächste VL: Rückblick auf die ganze Vorlesungsreihe & Klausurvorbereitung.

1 / …