MINT lernen

Übungen: Automaten in Java

Zehn Übungen zu switch, int[][] delta und Tracetabellen — vom Zuordnen bis zur Fehlersuche im Code.

Dein Fortschritt:
0 / 0 Aufgaben
1

Übungsaufgaben

Zehn Übungen zum Klicken, Zuordnen, Nachverfolgen und Knobeln — von AFB I bis AFB III. Jede Übung gibt sofort Rückmeldung; wenn Sie nicht weiterkommen, helfen die gestuften Tipps.

A1
Was macht welche Zeile?
AFB I

Jede Java-Zeile einer Automaten-Klasse setzt einen Teil des Modells um. Ordnen Sie jedem Code-Baustein seine Aufgabe im Automaten zu.

Ansatz: Suchen Sie zuerst die beiden Zeilen mit return: Eine davon steht in spalte, die andere am Ende von akzeptiert.
Weiter: Das Feld delta ist die Übergangstabelle: Zeile = Zustand, Spalte = Zeichen, Eintrag = Folgezustand.
A2
Codelücken: durch 3 teilbar
AFB I

Ein DEA über Σ = {0, 1} akzeptiert genau die Binärzahlen, die durch 3 teilbar sind. Zustand zr bedeutet: Die bisher gelesene Zahl lässt beim Teilen durch 3 den Rest r. Zeichen außerhalb von Σ führen in den nicht eingetragenen Fehlerzustand zF.

Übergangstabelle DurchDrei
Zustand01
z0z0z1
z1z2z0
z2z1z2

Geben Sie für jede Lücke der Java-Klasse den passenden Eintrag an.

Wählen Sie in jedem Menü den passenden Eintrag und prüfen Sie dann alle auf einmal.
Java · Klasse DurchDrei
public class DurchDrei {
    private int zustand;        // 0 = z0, 1 = z1, 2 = z2, 3 = zF

    public void uebergang(char c) {
        switch (zustand) {
            case 0:
                if (c == '0') { zustand = 0; }
                else if (c == '1') { zustand = ; }
                else { zustand = 3; }
                break;
            case 1:
                if (c == '0') { zustand = ; }
                else if (c == '1') { zustand = ; }
                else { zustand = 3; }
                break;
            case 2:
                if (c == '0') { zustand = ; }
                else if (c == '1') { zustand = 2; }
                else { zustand = 3; }
                break;
            default:
                zustand = ;
        }
    }

    public boolean akzeptiert(String wort) {
        zustand = 0;
        for (int i = 0; i < wort.length(); i++) {
            uebergang(wort.charAt(i));
        }
        return ;
    }
}
Aus der Tabelle: z0 –1→ z1, z1 –0→ z2, z1 –1→ z0, z2 –0→ z1. Typischer Fehler ist die Endzustandsprüfung zustand != 3: Sie akzeptiert jede gültige Binärzahl, nicht nur die durch 3 teilbaren. Endzustand ist allein z0 (Rest 0) — deshalb wird auch das leere Wort akzeptiert. Im default-Zweig bleibt zF zF: kein Weg zurück.
Ansatz: Lesen Sie jede Lücke als Tabellenfeld: Zeile = case, Spalte = das Zeichen im if.
Weiter: Endzustand ist nur der Zustand mit Doppelunterstrich in der Tabelle: z0, also Rest 0.
A3
Stimmt das? — Java-Details
AFB I

Es geht um die beiden Implementierungen aus dem Kapitel: switch in uebergang(char c) und Tabelle int[][] delta. Nennen Sie zu jeder Aussage, ob sie stimmt.

5 Aussagen nacheinander. Eine falsche Einschätzung reicht — dann starten Sie die Serie mit „Neue Runde“ neu.
Aussage 1 von 5

Die gefährlichste Aussage ist die erste: Das vergessene zustand = 0; fällt beim ersten Test nicht auf, weil Java int-Attribute mit 0 vorbelegt. Testen Sie deshalb immer mehrere Wörter hintereinander mit demselben Objekt.
Ansatz: Denken Sie an die Vorbelegung von Attributen in Java und an den Unterschied zwischen 'a' und "a".
Weiter: Ein Feldindex −1 ist in Java nie erlaubt; ein fehlendes break führt den nächsten case mit aus.
A4
Wie groß wird die Tabelle?
AFB I

Ein DEA prüft Uhrzeiten der Form hh:mm (z. B. 07:45). Er hat die Zustände z0 bis z6 und zusätzlich den Fehlerzustand zF. Σ besteht aus den zehn Ziffern und dem Doppelpunkt; jedes Zeichen bekommt eine eigene Spalte. Berechnen Sie, wie viele int-Werte das Feld delta speichert.

Überlegen Sie selbst und tragen Sie das Ergebnis ein — Enter prüft direkt.
8 Zustände (z0 bis z6 und zF) mal 11 Zeichen (10 Ziffern und „:“) ergibt 8 · 11 = 88 Einträge. Häufigster Fehler: 77 — dabei fehlt die Zeile für zF. Auch zF braucht eine vollständige Zeile, sonst gibt es beim Weiterlesen nach einem Fehler einen Absturz.
Ansatz: Zeilen = Zustände, Spalten = Zeichen von Σ. Zählen Sie beide sorgfältig.
Weiter: z0 bis z6 sind 7 Zustände — plus zF. Der Doppelpunkt ist das elfte Zeichen.
A5
Tracetabelle: ganze Zahlen
AFB II

Die Klasse GanzeZahl prüft ganze Zahlen mit optionalem Vorzeichen (z. B. -17, +3, 42).

Java · Klasse GanzeZahl
public class GanzeZahl {
    private int zustand;               // 0 = z0, 1 = z1, 2 = z2, 3 = zF
    //                         +  -  Ziffer
    private int[][] delta = { {1, 1, 2},     // z0
                              {3, 3, 2},     // z1
                              {3, 3, 2},     // z2
                              {3, 3, 3} };   // zF

    private int spalte(char c) {
        if (c == '+') { return 0; }
        if (c == '-') { return 1; }
        if (c >= '0' && c <= '9') { return 2; }
        return -1;
    }

    public boolean akzeptiert(String wort) {
        zustand = 0;
        for (int i = 0; i < wort.length(); i++) {
            int s = spalte(wort.charAt(i));
            if (s == -1) { zustand = 3; }
            else { zustand = delta[zustand][s]; }
        }
        return zustand == 2;
    }
}

Stellen Sie den Aufruf akzeptiert("-4+2") als Tracetabelle dar (Zustände als Zahlen 0–3, Rückgabe als true oder false).

Füllen Sie alle Felder aus und prüfen Sie dann. Enter in einem Feld prüft ebenfalls.
i0123
wort.charAt(i)'-''4''+''2'
s = spalte(…)
zustand danach
Rückgabe
Spalten: „-“ → 1, „4“ → 2, „+“ → 0, „2“ → 2. Zustände: 0 → 1 → 2 → 3 → 3. Das „+“ mitten im Wort führt aus z2 nach zF (delta[2][0] = 3) — und aus zF führt auch die Ziffer 2 nicht zurück. Typischer Fehler: nach der 2 wieder Zustand 2 eintragen, weil man nur auf das aktuelle Zeichen schaut statt auf die Zeile des aktuellen Zustands.
Ansatz: Erst spalte auswerten, dann in delta Zeile = alter Zustand, Spalte = s nachschlagen.
Weiter: Nach dem „+“ steht der Automat in Zeile 3 (zF). Diese Zeile enthält nur Dreien.
A6
Methode zustandsfolge
AFB II

Zur Fehlersuche soll die Klasse DurchDrei aus A2 eine zusätzliche Methode String zustandsfolge(String wort) erhalten. Für das Wort 110 soll sie den Text z0 z1 z0 z0 liefern — Startzustand zuerst, danach der Zustand nach jedem Zeichen. Implementieren Sie den Methodenrumpf, indem Sie die Zeilen ordnen.

Ziehen Sie die Karten in die richtige Reihenfolge — mit der Tastatur: ↑/↓ verschiebt, Shift+↑/↓ wechselt nur den Fokus.
1zustand = 0;
2String folge = "z" + zustand;
3for (int i = 0; i < wort.length(); i++) {
4 uebergang(wort.charAt(i));
5 folge = folge + " z" + zustand;
6}
7return folge;
Zwei Stellen verrutschen am häufigsten: Steht String folge = "z" + zustand; vor zustand = 0;, beginnt der Text mit dem Endzustand des vorigen Aufrufs. Und steht folge = … vor uebergang(…) in der Schleife, hängt die Folge einen Schritt hinterher: Für 110 käme z0 z0 z1 z0 heraus, der letzte Zustand fehlt.
Ansatz: Erst den Startzustand herstellen, dann ihn als Anfang des Texts notieren.
Weiter: In der Schleife muss der Übergang passieren, bevor der neue Zustand angehängt wird.
A7
Probelauf am Spielautomaten
AFB II

Ein Spielautomat zeigt nacheinander die Symbole K (Kirsche) und S (Stern). Die Klasse Glueck prüft, ob eine Symbolfolge gewinnt.

Java · Klasse Glueck
public class Glueck {
    private int zustand;
    //                         K  S
    private int[][] delta = { {1, 0},     // z0
                              {2, 0},     // z1
                              {3, 0},     // z2
                              {3, 3} };   // z3

    private int spalte(char c) {
        if (c == 'K') { return 0; }
        if (c == 'S') { return 1; }
        return -1;
    }

    public boolean akzeptiert(String wort) {
        zustand = 0;
        for (int i = 0; i < wort.length(); i++) {
            int s = spalte(wort.charAt(i));
            if (s == -1) { return false; }
            zustand = delta[zustand][s];
        }
        return zustand == 3;
    }
}

Wenden Sie den Code auf das Wort KKSKKKS an: Geben Sie die Zustandsnummer nach den genannten Anfangsstücken an und zuletzt den Rückgabewert.

Arbeiten Sie die Kette Schritt für Schritt ab: Erst wenn ein Schritt stimmt, wird der nächste freigeschaltet. Enter prüft.
  1. Zustand nach K
  2. Zustand nach KKS
  3. Zustand nach KKSKK
  4. Zustand nach KKSKKK
  5. Rückgabe von akzeptiert("KKSKKKS")
Der Automat zählt K in Folge; ein S setzt den Zähler zurück — außer in z3. Zeile z3 enthält nur Dreien: Wer einmal drei Kirschen hintereinander hatte, hat gewonnen, egal was folgt. Typischer Fehler: am Ende false antworten, weil das letzte Symbol ein S ist. Ohne Kenntnis der Zeile z3 sieht KKSKKKS nach „verloren“ aus.
Ansatz: Gehen Sie Zeichen für Zeichen: Zeile = aktueller Zustand, Spalte 0 für K, Spalte 1 für S.
Weiter: Schauen Sie sich die letzte Zeile von delta genau an, bevor Sie das abschließende S verarbeiten.
A8
Welche Sprache steckt im Code?
AFB II Mix

Von einer Automaten-Klasse über Σ = {a, b} kennen Sie nur die Übergangstabelle und die letzte Zeile von akzeptiert; akzeptiert setzt wie üblich zuerst zustand = 0;.

Java · Ausschnitt
    //                         a  b
    private int[][] delta = { {1, 0},     // z0 (Start)
                              {1, 2},     // z1
                              {1, 0} };   // z2
    …
    return zustand == 2;                  // Ende von akzeptiert

Analysieren Sie den Automaten und markieren Sie alle zutreffenden Aussagen.

Mehrere Antworten sind richtig. Markieren Sie alle zutreffenden und klicken Sie dann auf „Prüfen“.
Übersetzen Sie die Tabelle zurück in einen Zustandsgraphen: z1 = „zuletzt a“, z2 = „zuletzt ab“. Ein b nach ab führt zurück nach z0 — deshalb wird abb abgelehnt, obwohl es ab enthält. z0 ist kein Fehlerzustand: Mit a kommt man jederzeit wieder heraus. Das leere Wort endet in z0 und wird abgelehnt.
Ansatz: Probieren Sie kurze Wörter systematisch aus: ε, a, b, ab, abb, aab …
Weiter: Beschreiben Sie jeden Zustand mit dem, was er sich über die letzten Zeichen merkt.
A9
Fehlersuche: Dezimalzahlen
AFB III

Ein DEA soll Dezimalzahlen erkennen: mindestens eine Ziffer, danach optional ein Komma, auf das mindestens eine Ziffer folgt (12, 3,14 ja; ,5, 1,, 1,2,3 nein). Zustände: z0 Start, z1 „nur Ziffern“ (Endzustand), z2 „Komma gelesen“, z3 „Nachkommaziffern“ (Endzustand), zF = 4. Zeilen 1–7 bilden uebergang(char c), Zeilen 8–10 den Rumpf von akzeptiert. Überprüfen Sie den Code — drei Zeilen sind fehlerhaft.

In diesem Code stecken Fehler. Klicken Sie genau die fehlerhaften Zeilen an — die richtigen müssen stehen bleiben.
Die drei Fehler wirken ganz verschieden: <= führt zum Absturz, das fehlende break macht nur Wörter mit Komma kaputt, die falsche Rückgabe nur Wörter ohne Komma. Wer nur mit 3,14 testet, findet höchstens einen davon. Zeile 7 ohne break ist dagegen korrekt: Der letzte Fall braucht keins.
Ansatz: Verfolgen Sie 1,5 und 12 im Kopf Zeichen für Zeichen durch den Code.
Weiter: Achten Sie auf ein fehlendes break, auf die Schleifengrenze und darauf, welche Zustände Endzustände sind.
A10
Umbauen ohne Folgen?
AFB III Trick

Das ist die korrigierte Klasse für Dezimalzahlen aus A9 (zF = 4):

Java · Klasse Dezimalzahl (korrigiert)
public void uebergang(char c) {
    boolean ziffer = c >= '0' && c <= '9';
    switch (zustand) {
        case 0: if (ziffer) { zustand = 1; } else { zustand = 4; } break;
        case 1: if (ziffer) { zustand = 1; } else if (c == ',') { zustand = 2; } else { zustand = 4; } break;
        case 2: if (ziffer) { zustand = 3; } else { zustand = 4; } break;
        case 3: if (ziffer) { zustand = 3; } else { zustand = 4; } break;
        default: zustand = 4;
    }
}
public boolean akzeptiert(String wort) {
    zustand = 0;
    for (int i = 0; i < wort.length(); i++) { uebergang(wort.charAt(i)); }
    return zustand == 1 || zustand == 3;
}

Beurteilen Sie jede Änderung: Liefert akzeptiert danach für jedes Wort und bei jedem Aufruf dasselbe Ergebnis wie vorher?

Ziehen Sie jede Karte in den passenden Korb — oder wählen Sie sie mit Enter aus und drücken dann die Ziffer des Korbs (0 legt sie zurück).
1Ergebnis bleibt immer gleich
2Ergebnis ändert sich
Zwei Fallen: default zu streichen schadet nicht, weil in zF dann einfach kein Fall greift und zustand 4 bleibt. Und das Rückwärtslesen ändert nichts, weil die Sprache symmetrisch ist: Ziffern, optional Komma und Ziffern — rückwärts gelesen ist das wieder genau so aufgebaut. zustand % 2 == 1 trifft genau 1 und 3. Dagegen akzeptiert zustand != 4 auch 1, (z2) und das leere Wort (z0); der Konstruktor-Umbau lässt den zweiten Aufruf im alten Zustand starten.
Ansatz: Probieren Sie jede Änderung mit einem Wort aus, bei dem sie „greifen“ würde — etwa 1,, 1,5,3 oder einem zweiten Aufruf.
Weiter: Rückwärts gelesen wird aus 3,14 das Wort 41,3 — gehört es zur Sprache?