Benutzer-Werkzeuge

Webseiten-Werkzeuge


einstieg:geschachtelt:start

Dies ist eine alte Version des Dokuments!


Ineinandergeschachtelte Schleifen

Es kommt häufig vor, dass ein Programmteil wiederholt werden muss, in dem selbst schon eine Schleife steckt. Das ist kein Problem, denn Schleifen kann man beliebig ineinander schachteln. Wofür das gut ist und wie es geht, zeige ich Dir am besten an ein paar Beispielen.

Beispiel 1: Einmaleinstabelle

Kennst Du noch die Bleistifte mit den winzigen Einmaleinstabellen drauf, die in der Grundschule streng verboten sind? Die Einmaleinstabelle sieht so aus:

1  2  3  4 5  6  7  8  9  10
2  4  6  8  10 12 14 16 18 20
3  6  9  12 15 18 21 24 27 30
4  8  12 16 20 24 28 32 36 40
5  10 15 20 25 30 35 40 45 50
6  12 18 24 30 36 42 48 54 60
7  14 21 28 35 42 49 56 63 70
8  16 24 32 40 48 56 64 72 80 ​
9  18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100 

Wir wollen ein Programm schreiben, das die Einmaleinstabelle auf dem Bildschirm ausgibt.

Strategie: Divide and conquer (Teile und herrsche)

Oft lässt sich ein Problem nur lösen, indem man es in kleine, beherrschbare Teilprobleme zerlegt. Diese Problemlösestrategie nennt man command and conquer (mehr dazu hier).

Wir denken uns die Einmaleinstabelle in einzelne Zeilen ("Einmaleinsreihen") zerlegt und schreiben zunächst ein Programm, das eine einzelne Einmaleinsreihe ausgibt.

Der Wert der Variable 'e' bestimmt die Einmaleinsreihe, die ausgegeben wird.

Probiere es aus, indem Du die 6 in Zeile 1 abänderst und das Programm neu startest! Führe das Programm auch mal in Einzelschritten aus ("Step over": ) und sieh' Dir im Variablen-Tab an, welche Werte die Variablen e und i während des Programmablaufs annehmen!

Um die komplette Einmaleinstabelle auszugeben, müssen wir den obigen Programmteil zuerst für e == 1 ausführen, dann für e == 2, usw.:

War's das schon?

Eigentlich ist die Aufgabe jetzt schon gelöst: Die Einmaleinstabelle wird korrekt ausgegeben. Trotzdem hoffe ich, dass Ihr mit der gefundenen Lösung genauso unzufrieden seid wie ich:

  • Der Code ist hochgradig redundant.
  • Wenn wir später in der for-Schleife etwas ändern wollen (z.B. weil wir einen Fehler entdeckt haben), dann müssen wir es 10-Mal ausbessern.
  • Das Programm belegt sehr viel Speicherplatz.



Es muss doch möglich sein, den Computer anzuweisen, den Programmblock aus dem ersten Beispiel oben einfach 10-mal zu wiederholen!

Bessere Lösung: zwei ineinandergeschachtelte Schleifen

Schiebe den Geschwindigkeitsregler (neben dem Startbutton) auf ca. 6 Schritte pro Sekunde und führe das Programm aus. Wenn das Programm langsam genug ausgeführt wird, wird die gerade ausgeführte Anweisung jeweils grün hinterlegt.

  • Beobachte, nach welchem Muster der grüne Balken sich durchs Programm bewegt!
  • Führe das Programm auch im Einzelschritt bei geöffnetem Tab "Variablen" aus und schau' Dir bei jedem Schritt die Werte der Variablen e und i an!

Schalte rechts auf den "Variablen"-Tab und führe dann das Programm in Einzelschritten aus ("Step over": ). Beobachte genau den Wert der Variable n!

Erklärung der einzelnen Anweisungen
  1. int n = 1;

Die Variable n benutzen wir, um zu zählen, wie oft wir schon wiederholt haben. n == 1 bedeutet, dass wir im 1. Wiederholungsdurchgang sind.

  1. while(n <= 10){
  2. println("Hallo Welt!");
  3. n = n + 1;
  4. }

Die Anweisung while(n ⇐ 10) bedeutet: Wiederhole die Anweisungen zwischen den nachfolgenden {}, solange n kleiner oder gleich 10 ist. Damit die Anweisungen nicht unendlich oft wiederholt werden, müssen wir dafür sorgen, dass die Aussage n ⇐ 10 irgendwann nicht mehr zutrifft. Deshalb erhöhen wir am Ende der Schleife n um 1, indem wir schreiben: n = n + 1;.

  1. println("Fertig!", Color.green);

Sobald die Bedingung hinter while nicht mehr zutrifft, werden die Anweisungen in {} übersprungen und der Computer fährt mit den Anweisungen fort, die hinter den {} stehen. In diesem Fall gibt er "Fertig!" aus.

Mit Hilfe der while-Schleife können wir eine Sequenz von Anweisungen öfters wiederholen lassen.

while(Bedingung){
   //Anweisungen
}

Die Anweisungen werden wiederholt, solange die Bedingung zutrifft, also den Wert true hat.

Beachte: Schon vor der Ersten Ausführung der Anweisungen wird überprüft, ob die Bedingung zutrifft. Hat sie schon zu Beginn den Wert false, so werden die Anweisungen in den {} gar nicht ausgeführt.

Kleine Aufgabe

Ändere das Programm oben so ab, dass es 8-mal Deinen Namen in Deiner Lieblingsfarbe ausgibt!

Beispiel 2: Varianten...

Eine Schleife kann nicht nur immer wieder exakt dasselbe wiederholen. Man kann beispielsweise die Zählvariable in der Schleife benutzen, um auszugeben, wie oft die Schleife schon durchlaufen wurde:

Die drei print-Anweisungen kann man übrigens auch zu einer einzigen Anweisung zusammenfassen:

   println("Das ist der " + z + "-te Wiederholungsschritt");

Addieren von Zeichenketten

In Java bewirkt der Operator + bei Zeichenketten, dass sie hintereinandergehängt ("konkateniert") werden. Der Term "Das ist " + "Text" hat daher den Wert "Das ist Text".

Wird eine Variable vom Datentyp int zu einer Zeichenkette addiert, so wird die Variable zuerst in eine Zeichenkette umgewandelt und anschließend werden die beiden Zeichenketten hintereinandergehängt.

int z = 12;
println("Das ist die Zahl " + z);

gibt also aus: Das ist die Zahl 12.

Beispiel 3: Quadratzahlen

Oft ist es nützlich, noch zusätzliche Variablen zu deklarieren, die bei jedem Wiederholungsschritt geändert werden. Wir schreiben ein Programm, das die ersten 10 Zweierpotenzen ausgibt, also $2^0 = 1$, $2^1 = 2$, $2^2 = 4$, $2^3 = 8$ usw.

Schalte rechts auf den "Variablen"-Tab und führe dann das Programm in Einzelschritten aus ("Step over": ). Beobachte genau den Wert der Variablen i und zp!

Wenn das Programm pausiert (etwa nach Klick auf den Pause-Button oder bei der Ausführung in Einzelschritten) kannst Du den Wert von Variablen sehen, indem Du im Programmtext mit der Maus auf die Variable fährst und etwas wartest. Es öffnet sich ein Tooltip mit dem Wert der Variable (siehe Bild rechts).

Aufgaben zur while-Schleife

B. Die while-Schleife mit Endbedingung

Man kann die while-Schleife auch so schreiben, dass die Bedingung zum Fortfahren der Schleife jeweils erst am Ende jedes Wiederholungsschrittes überprüft wird.

Beispiel 5: while-Schleife mit Endbedingung (do...while-Schleife)

Wir zählen wieder von 1 bis 10:

C. Die for-Schleife

Die while-Schleife hat zwei große Nachteile:

  • Zum bloßen Zählen ist sie sehr umständlich, da insgesamt drei Zeilen benötigt werden:
int i = 0;         // Deklaration der Zählvariable
while(i <= 10){    // Bedingung
   // Anweisungen
   i++;            // Erhöhung der Zählvariable
}
  • Oft stehen zwischen der Deklaration der Zählvariable und der Bedingung sowie zwischen der Bedingung und der Erhöhung der Zählvariable sehr viele Anweisungen und es ist schwer, "auf einen Blick" zu erfassen, wie oft wiederholt wird und welche Werte die Zählvariable bei jedem Wiederholungsschritt annimmt.

Für alle Anwendungsfälle, in denen auf irgendeine Art und Weise gezählt wird, verwendet man daher üblicherweise eine Kurzschreibweise der while-Schleife, die for-Schleife. Hier eine Gegenüberstellung der beiden. Beide Programme sind gleichwertig:

While-Schleife For-Schleife

Die for-Schleife ist eine Kurzform der while-Schleife. Sie besteht aus drei Bestandteilen:

for(Startanweisung; Bedingung; Anweisung am Ende jedes Wiederholungsschrittes){
   // Anweisungen
}
  • Die Startanweisung wird genau 1-mal zu Beginn der Schleife aufgerufen.
  • Die Bedingung wird vor jedem Wiederholungsschritt ausgewertet. Ist ihr Wert true, so werden die Anweisungen in den {} ausgeführt. Ist der Wert false, so werden die Anweisungen in den {} übersprungen und es wird mit der Anweisung hinter der for-Schleife fortgefahren.
  • Die Anweisung am Ende jedes Wiederholungsschrittes wird am Ende jedes Wiederholungsschrittes ausgeführt.

Für Einsteiger ist die for-Schleife oft schwer zu verstehen, weil ihre drei Bestandteile jeweils ganz unterschiedliche Bedeutung haben. Noch dazu ist der 1. und 3. Bestandteil eine Anweisung, der 2. Bestandteil eine Bedingung (genauer: eine Aussage).

Lass' Dich nicht entmutigen: Meist wird die for-Schleife zum Zählen benutzt und sieht so oder ähnlich aus:

for(int i = 0; i < 10; i++){
   // Anweisungen
}

Dieses Muster (das in diesem Fall die Anweisungen für i-Werte von 0 bis 9 durchführt) wirst Du sehr schnell beherrschen und - von diesem Muster ausgehend - bald auch schwierigere Konstruktionen mit for verstehen.

Führe die folgenden Programme in Einzelschritten aus ("Step over": ), und zwar

  • zunächst mit offenem Tab "Ausgabe" auf der rechten Seite
  • dann mit offenem Tab "Variablen" auf der rechten Seite.

Beobachte genau, was jeder Einzelne Programmschritt bewirkt!

Beispiel 6: Zählen mit "for"

Wir schreiben den Text "Hallo Welt!" 10-mal untereinander in die Ausgabe. Mit der Variablen i zählen wir dabei, wie oft wir ihn schon ausgegeben haben.

Erklärung

Die for-Schleife bewirkt, dass der Rechner folgendes macht:

AnweisungErklärungWert von i nach der Anweisung
int i = 1;Die Startanweisung wird genau ein Mal zu Beginn ausgeführt.1
Prüfe: Ist i ⇐ 10? Das Ergebnis der Prüfung ist true, da $1 \le 10$ ist. Daher wird als nächste die Anweisung in {} ausgeführt.1
println("Hallo Welt (zum " + i + "-ten Mal)!"); Es wird ausgegeben: Hallo Welt (zum 1. Mal)! 1
i++; Am Ende des Wiederholungsschrittes wird i++ ausgeführt und damit der Wert von i um 1 erhöht. Der Rechner setzt die Ausführung in Zeile 1 fort.2
Prüfe: Ist i ⇐ 10? Das Ergebnis der Prüfung ist true, da $2 \le 10$ ist. Daher wird als nächste die Anweisung in {} ausgeführt.2
println("Hallo Welt (zum " + i + "-ten Mal)!"); Es wird ausgegeben: Hallo Welt (zum 2. Mal)! 2
i++; Am Ende des Wiederholungsschrittes wird i++ ausgeführt und damit der Wert von i um 1 erhöht. Der Rechner setzt die Ausführung in Zeile 1 fort.3

usw…

Die letzten Schritte sehen so aus:

println("Hallo Welt (zum " + i + "-ten Mal)!"); Es wird ausgegeben: Hallo Welt (zum 9. Mal)! 9
i++; Am Ende des Wiederholungsschrittes wird i++ ausgeführt und damit der Wert von i um 1 erhöht. Der Rechner setzt die Ausführung in Zeile 1 fort.10
Prüfe: Ist i ⇐ 10? Das Ergebnis der Prüfung ist true, da $10 \le 10$ ist. Daher wird als nächste die Anweisung in {} ausgeführt.10
println("Hallo Welt (zum " + i + "-ten Mal)!"); Es wird ausgegeben: Hallo Welt (zum 10. Mal)! 10
i++; Am Ende des Wiederholungsschrittes wird i++ ausgeführt und damit der Wert von i um 1 erhöht. Der Rechner setzt die Ausführung in Zeile 1 fort.11
Prüfe: Ist i ⇐ 10? Das Ergebnis der Prüfung ist false, da nicht $11 \le 10$ ist. Daher wird jetzt die Anweisung in {} übersprungen und es geht in Zeile 4 weiter!11
println("Fertig!", Color.lightgreen);

Beispiel 7: Zählen im Dreierschritt

Du erinnerst Dich sicher: n += 3 ist eine Kurzschreibweise für n = n + 3 und bewirkt, dass der Wert der Variable n um 3 erhöht wird.

Beispiel 8: Berechnung von 8!

Berechnung von Fakultäten

Die Faktultät einer Zahl $n \in \mathbb{N}$, kurz $n!$, ist folgendermaßen definiert: $$n! = 1 \cdot 2 \cdot 3 \cdot 4 \cdot \ldots \cdot n$$ Es ist beispielsweise $5! = 1 \cdot 2 \cdot 3 \cdot 4 \cdot 5 = 120$.

Probiere das Programm wieder in Einzelschritten aus und schau' Dir die Belegung der Variablen nach jedem Schritt an!

  • Du kannst die 8 in der ersten Zeile natürlich auch durch eine andere Zahl ersetzen!
  • Warum wird der Variablen fakultät in Zeile 2 der Startwert 1 zugeordnet und nicht 0?
    (Falls Du nicht auf die Antwort kommst, probier' es aus, indem Du die 1 im Programm durch 0 ersetzt!)
einstieg/geschachtelt/start.1593157256.txt.gz · Zuletzt geändert: 2021/12/29 11:29 (Externe Bearbeitung)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki