Entwicklung und Umsetzung von Algorithmen

Dieser Teil dauert ebenfalls 90 Minuten und umfasst 100 Punkte (10%).

Hier geht es um die praktische Programmierung - Algorithmen, SQL, OOP und Testing.


SQL - Strukturierte Datenbankabfragen

SQL ist die Sprache um mit Datenbanken zu kommunizieren - unverzichtbar für jeden Entwickler.

Wichtig - Prüfungsrelevant

In der AP2 gibt es ein 2-seitiges SQL-Detailblatt mit allen Befehlen! 👈

Tabellen erstellen und ändern

SQL CREATE TABLE

Erstellt eine neue Tabelle in der Datenbank.

CREATE TABLE Kunde (
    KundenID INT PRIMARY KEY,
    Name VARCHAR(100) NOT NULL,
    Email VARCHAR(100),
    Geburtsdatum DATE
);

SQL ALTER TABLE

Ändert bestehende Tabellen - Spalten hinzufügen oder entfernen.

-- Spalte hinzufügen
ALTER TABLE Kunde ADD Telefon VARCHAR(20);

-- Spalte löschen
ALTER TABLE Kunde DROP COLUMN Telefon;

-- Spalte ändern
ALTER TABLE Kunde MODIFY Email VARCHAR(150);

INDEX erstellen

Indizes machen Abfragen schneller - wie ein Stichwortverzeichnis im Buch.

CREATE INDEX idx_kunde_name ON Kunde(Name);

Daten manipulieren

SQL INSERT

Fügt neue Datensätze in Tabellen ein.

-- Einzelner Datensatz
INSERT INTO Kunde (KundenID, Name, Email)
VALUES (1, 'Max Mustermann', '[email protected]');

-- Mehrere Datensätze
INSERT INTO Kunde (KundenID, Name, Email) VALUES
    (2, 'Anna Schmidt', '[email protected]'),
    (3, 'Tom Meyer', '[email protected]');

SQL UPDATE

Ändert bestehende Datensätze.

UPDATE Kunde
SET Email = '[email protected]'
WHERE KundenID = 1;
Warnung

Vergiss nie die WHERE-Klausel - sonst änderst du ALLE Datensätze!

SQL DELETE

Löscht Datensätze aus Tabellen.

DELETE FROM Kunde WHERE KundenID = 3;

Daten abfragen

SQL SELECT - Die Basis

Holt Daten aus der Datenbank.

-- Alle Spalten
SELECT * FROM Kunde;

-- Bestimmte Spalten
SELECT Name, Email FROM Kunde;

-- Mit Bedingung
SELECT Name FROM Kunde WHERE KundenID > 5;

SQL WHERE - Filtern

Filtert Ergebnisse nach Bedingungen.

-- Vergleiche
SELECT * FROM Kunde WHERE Alter > 18;
SELECT * FROM Kunde WHERE Name = 'Max';

-- Kombinationen
SELECT * FROM Kunde WHERE Alter > 18 AND Stadt = 'Berlin';
SELECT * FROM Kunde WHERE Stadt = 'Berlin' OR Stadt = 'Hamburg';

-- LIKE für Textsuche
SELECT * FROM Kunde WHERE Name LIKE 'M%'; -- Beginnt mit M
SELECT * FROM Kunde WHERE Email LIKE '%@gmail.com'; -- Endet mit @gmail.com

SQL JOIN - Tabellen verbinden

Kombiniert Daten aus mehreren Tabellen.

INNER JOIN - Nur übereinstimmende Datensätze:

SELECT Kunde.Name, Bestellung.BestellNr
FROM Kunde
INNER JOIN Bestellung ON Kunde.KundenID = Bestellung.KundenID;

LEFT JOIN - Alle aus linker Tabelle:

SELECT Kunde.Name, Bestellung.BestellNr
FROM Kunde
LEFT JOIN Bestellung ON Kunde.KundenID = Bestellung.KundenID;

RIGHT JOIN - Alle aus rechter Tabelle:

SELECT Kunde.Name, Bestellung.BestellNr
FROM Kunde
RIGHT JOIN Bestellung ON Kunde.KundenID = Bestellung.KundenID;

SQL ORDER BY - Sortieren

Sortiert Ergebnisse aufsteigend oder absteigend.

-- Aufsteigend (Standard)
SELECT * FROM Kunde ORDER BY Name;

-- Absteigend
SELECT * FROM Kunde ORDER BY Alter DESC;

-- Mehrere Spalten
SELECT * FROM Kunde ORDER BY Stadt, Name;

SQL GROUP BY - Gruppieren

Fasst Datensätze zusammen - oft mit Aggregatfunktionen.

-- Anzahl Kunden pro Stadt
SELECT Stadt, COUNT(*) as AnzahlKunden
FROM Kunde
GROUP BY Stadt;

-- Durchschnittsalter pro Stadt
SELECT Stadt, AVG(Alter) as Durchschnittsalter
FROM Kunde
GROUP BY Stadt;

Aggregatfunktionen:

SQL HAVING - Gruppierungen filtern

Wie WHERE, aber für gruppierte Ergebnisse.

-- Nur Städte mit mehr als 10 Kunden
SELECT Stadt, COUNT(*) as AnzahlKunden
FROM Kunde
GROUP BY Stadt
HAVING COUNT(*) > 10;
Merkhilfe

WHERE filtert VOR Gruppierung, HAVING filtert NACH Gruppierung.


Algorithmen

Ein Algorithmus ist eine Schritt-für-Schritt-Anleitung zur Lösung eines Problems.

Eigenschaften eines guten Algorithmus:

Sortieralgorithmen

Bubble Sort

Vergleicht benachbarte Elemente und tauscht sie wenn nötig - wie Blasen die aufsteigen.

Funktionsweise:

  1. Vergleiche Element mit Nachbar
  2. Tausche wenn in falscher Reihenfolge
  3. Wiederhole bis sortiert

Komplexität:

void bubbleSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        for (int j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // Tauschen
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

Selection Sort

Sucht immer das kleinste Element und setzt es an die richtige Position.

🆕 Detailliert im Katalog 2025!

Funktionsweise:

  1. Finde kleinstes Element
  2. Tausche es an erste Position
  3. Wiederhole für restliche Elemente

Komplexität:

void selectionSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        // Tauschen
        int temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
}

Insertion Sort

Fügt Elemente eins nach dem anderen an die richtige Stelle ein - wie Karten sortieren.

🆕 Detailliert im Katalog 2025!

Funktionsweise:

  1. Nehme nächstes Element
  2. Suche richtige Position in sortiertem Teil
  3. Füge es dort ein

Komplexität:

void insertionSort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        int key = arr[i];
        int j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

Suchalgorithmen

Lineare Suche

Durchsucht Liste Element für Element von Anfang bis Ende.

Komplexität: O(n)

int linearSearch(int[] arr, int target) {
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == target) {
            return i; // Gefunden
        }
    }
    return -1; // Nicht gefunden
}

Binäre Suche

Halbiert Suchbereich in jedem Schritt - funktioniert NUR bei sortierten Arrays!

Komplexität: O(log n)

Funktionsweise:

  1. Schaue in die Mitte
  2. Ist Element kleiner? → Linke Hälfte
  3. Ist Element größer? → Rechte Hälfte
  4. Wiederhole bis gefunden
int binarySearch(int[] arr, int target) {
    int left = 0;
    int right = arr.length - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;

        if (arr[mid] == target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

Komplexitätsanalyse - O-Notation

Beschreibt wie langsam ein Algorithmus wird wenn Daten größer werden.

Die wichtigsten Komplexitäten:

Notation Name Beispiel Beschreibung
O(1) Konstant Array-Zugriff Immer gleich schnell
O(log n) Logarithmisch Binäre Suche Sehr effizient
O(n) Linear Lineare Suche Proportional zur Größe
O(n log n) Quasi-Linear Quicksort, Mergesort Gute Sortierung
O(n²) Quadratisch Bubble Sort Langsam bei großen Daten

Best/Average/Worst Case

Algorithmen können je nach Input unterschiedlich schnell sein.


OOP - Objektorientierte Programmierung

OOP organisiert Code in Objekten - jedes Objekt hat Daten und Funktionen.

Die 4 Säulen der OOP:

Kapselung

Verstecke interne Details - nur das Nötige nach außen zeigen.

🆕 Explizit betont im Katalog 2025!

Vorteile:

public class BankKonto {
    private double kontostand; // Privat!

    public void einzahlen(double betrag) {
        if (betrag > 0) {
            kontostand += betrag;
        }
    }

    public double getKontostand() {
        return kontostand;
    }
}

Vererbung

Kindklassen erben Eigenschaften von Elternklassen - verhindert Code-Duplikation.

class Tier {
    String name;

    void atmen() {
        System.out.println("Atmet");
    }
}

class Hund extends Tier {
    void bellen() {
        System.out.println("Wuff!");
    }
}

Polymorphie

Ein Interface, viele Formen - gleicher Aufruf, unterschiedliches Verhalten.

class Tier {
    void machGeraeusch() {
        System.out.println("...");
    }
}

class Hund extends Tier {
    void machGeraeusch() {
        System.out.println("Wuff!");
    }
}

class Katze extends Tier {
    void machGeraeusch() {
        System.out.println("Miau!");
    }
}

Abstraktion

Komplexität verstecken - zeige nur das Wesentliche.

abstract class Form {
    abstract double berechneFlaeche();
}

class Kreis extends Form {
    double radius;

    double berechneFlaeche() {
        return Math.PI * radius * radius;
    }
}

Programmierung - Kontrollstrukturen

Kontrollstrukturen steuern den Ablauf deines Programms.

Verzweigungen

if-else

if (alter >= 18) {
    System.out.println("Volljährig");
} else {
    System.out.println("Minderjährig");
}

switch-case

switch (tag) {
    case 1:
        System.out.println("Montag");
        break;
    case 2:
        System.out.println("Dienstag");
        break;
    default:
        System.out.println("Anderer Tag");
}

Schleifen

for-Schleife

Wenn du weißt wie oft wiederholt werden soll.

for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

while-Schleife

Wiederholt solange Bedingung wahr ist.

while (zaehler < 100) {
    zaehler++;
}

do-while-Schleife

Führt Code mindestens einmal aus.

do {
    System.out.println("Mindestens einmal");
} while (false);

Testing

Tests finden Fehler früh - je später ein Fehler gefunden wird, desto teurer.

Unit-Tests

Testet einzelne Funktionen oder Methoden isoliert.

@Test
public void testAddition() {
    Calculator calc = new Calculator();
    assertEquals(5, calc.add(2, 3));
}

Black Box Test

Testen ohne Code zu kennen - nur Eingabe und erwartete Ausgabe.

Vorteile:

Nachteile:

White Box Test

Testen mit Code-Kenntnis - alle Pfade durchgehen.

Vorteile:

Nachteile:

Last-/Performancetests

Testen wie System unter Last reagiert.

Was wird getestet:


Datenstrukturen

Wie du Daten organisierst beeinflusst Performance und Wartbarkeit.

Arrays

Feste Größe, schneller Zugriff über Index.

int[] zahlen = {1, 2, 3, 4, 5};
int erste = zahlen[0]; // Zugriff: O(1)

Vorteile:

Nachteile:

Listen

Variable Größe, dynamisch erweiterbar.

ArrayList<String> liste = new ArrayList<>();
liste.add("Element 1");
liste.add("Element 2");

LinkedList:

ArrayList:

Stack

Last In, First Out (LIFO) - wie ein Stapel Teller.

Operationen:

Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
int top = stack.pop(); // 2

Queue

First In, First Out (FIFO) - wie eine Warteschlange.

Operationen:

Queue<String> queue = new LinkedList<>();
queue.add("Erster");
queue.add("Zweiter");
String naechster = queue.poll(); // "Erster"

Fehlerbehandlung

Fehler passieren - wichtig ist wie du damit umgehst.

try-catch-finally

Fange Fehler ab bevor das Programm abstürzt.

try {
    int result = 10 / 0; // Division durch 0
} catch (ArithmeticException e) {
    System.out.println("Fehler: " + e.getMessage());
} finally {
    System.out.println("Wird immer ausgeführt");
}

Struktur:

Exception-Hierarchie


Cyber-physische Systeme

Verbindung zwischen Software und physischer Welt - Sensoren und Aktoren.

🆕 Neu für FIAE im Katalog 2025!

Sensoren

Sammeln Daten aus der Umwelt.

Beispiele:

Aktoren

Führen physische Aktionen aus.

Beispiele:

Bibliotheken für CPS

Nutze fertige Bibliotheken statt alles selbst zu programmieren.

Beispiele:

Abfragerhythmus planen

Wie oft sollen Sensoren abgefragt werden?

Überlegungen:

// Alle 100ms Sensor abfragen
while (true) {
    int temperatur = sensor.readTemperature();
    if (temperatur > 30) {
        motor.turnOn(); // Lüfter an
    }
    Thread.sleep(100);
}

Monitoring

Überwache deine Systeme - finde Probleme bevor Nutzer sie merken.

🆕 Festlegung Monitoringdaten verstärkt im Katalog 2025!

Was monitoren?

Schwellwerte festlegen

Definiere Grenzwerte ab wann Alarm geschlagen wird.

🆕 Verstärkt im Katalog 2025!

Beispiele:

if (cpu_usage > 80) {
    sendAlert("CPU-Auslastung kritisch: " + cpu_usage + "%");
}

if (response_time > 2000) {
    logWarning("Langsame Antwortzeit: " + response_time + "ms");
}

Monitoring-Tools


Pseudocode

Algorithmen in einfacher Sprache aufschreiben - vor dem Programmieren.

Vorteile:

Beispiel: Lineare Suche in Pseudocode

FUNKTION linearesuche(liste, zielwert)
    FÜR JEDES element IN liste:
        WENN element == zielwert:
            GEBE position ZURÜCK
    GEBE -1 ZURÜCK  // Nicht gefunden

Beispiel: Bubble Sort in Pseudocode

FUNKTION bubblesort(liste)
    n = länge(liste)
    FÜR i VON 0 BIS n-1:
        FÜR j VON 0 BIS n-i-1:
            WENN liste[j] > liste[j+1]:
                TAUSCHE liste[j] MIT liste[j+1]