Ü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.
Jede Java-Zeile einer Automaten-Klasse setzt einen Teil des Modells um. Ordnen Sie jedem Code-Baustein seine Aufgabe im Automaten zu.
zustand = 0; für „den Fehlerzustand setzen“ zu halten. Die Zahl 0 steht hier für z0, also den Startzustand — welcher Zustand welche Nummer hat, legt nur der Kommentar am Attribut fest. Ebenso ist return -1; kein Zustand, sondern ein Signal an akzeptiert, dass das Zeichen nicht zu Σ gehört.return: Eine davon steht in spalte, die andere am Ende von akzeptiert.delta ist die Übergangstabelle: Zeile = Zustand, Spalte = Zeichen, Eintrag = Folgezustand.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.
| Zustand | 0 | 1 |
|---|---|---|
| z0 | z0 | z1 |
| z1 | z2 | z0 |
| z2 | z1 | z2 |
Geben Sie für jede Lücke der Java-Klasse den passenden Eintrag an.
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 ; } }
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.case, Spalte = das Zeichen im if.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.
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.break führt den nächsten case mit aus.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.
Die Klasse GanzeZahl prüft ganze Zahlen mit optionalem Vorzeichen (z. B. -17, +3, 42).
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).
| i | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
wort.charAt(i) | '-' | '4' | '+' | '2' |
s = spalte(…) | ||||
zustand danach | ||||
| Rückgabe | ||||
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.spalte auswerten, dann in delta Zeile = alter Zustand, Spalte = s nachschlagen.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.
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.Ein Spielautomat zeigt nacheinander die Symbole K (Kirsche) und S (Stern). Die Klasse Glueck prüft, ob eine Symbolfolge gewinnt.
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.
-
Zustand nach
K -
Zustand nach
KKS -
Zustand nach
KKSKK -
Zustand nach
KKSKKK -
Rückgabe von
akzeptiert("KKSKKKS")
false antworten, weil das letzte Symbol ein S ist. Ohne Kenntnis der Zeile z3 sieht KKSKKKS nach „verloren“ aus.delta genau an, bevor Sie das abschließende S verarbeiten.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;.
// 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.
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.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.
<= 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.1,5 und 12 im Kopf Zeichen für Zeichen durch den Code.break, auf die Schleifengrenze und darauf, welche Zustände Endzustände sind.Das ist die korrigierte Klasse für Dezimalzahlen aus A9 (zF = 4):
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?
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.1,, 1,5,3 oder einem zweiten Aufruf.3,14 das Wort 41,3 — gehört es zur Sprache?