Document

Werbung
CS1005
Objektorientierte Programmierung
Bachelor of Science (Informatik)
Iteration und Rekursion
Seite 1
Th Letschert
While-Schleife
Schleife, While-Schleife
Schleife: Eine Anweisung / Anweisungsfolge wiederholt ausführen
While-Schleife
Zahl der Durchläufe wird vom Wert einer Bedingung gesteuert
Allgemeine Form
auch: „Schleifenkörper“
while ( Bedingung ) Anweisung(-sfolge)
Beispiel
int zaehler = 0;
System.out.println("Die ersten 15 Quadratzahlen:");
while (zaehler < 15) {
zaehler = zaehler + 1;
System.out.println(zaehler + " -> "
+ zaehler * zaehler);
}
Seite 2
While-Schleife
Schleife, While-Schleife
Beispiel: Die Summe der ersten n natürlichen Zahlen
int n = 5;
int sum = 0;
int i
= 0;
Angenommen n=5: Welche
Variablen haben welche
Werte im Laufe einer
Berechnung?
while (i < n) {
i = i + 1;
sum = sum + i;
}
System.out.println("Summe 1 ... "
+ n + " = " + sum);
n
i
sum
5
5
5
0
1
2
···
0
1
3
Angenommen die Anweisungen in der Schleife
werden vertauscht. Was passiert? Ist Berechnung
noch korrekt ? Wenn nein: warum nicht ?
Seite 3
Schleife
Schleife und Wertverlaufstabelle
Tabelle mit Variablen und ihren wechselnden Werten
n
i
sum
5
0
0
5
1
1
5
2
3
5
3
6
5
4
10
5
5
15
Schleifenende
Einstieg
erste Zeile
n
= 5
sum = 0
i
= 0
Schleifenkörper
von Zeile
zu Zeile
while ( i < n ) {
i = i+1
sum = sum + i
}
Schleifenende
Bedingung nicht mehr
erfüllt, keine weitere Zeile
Seite 4
Schleife
Konstruktion der Schleife aus einer Tabelle
Welche Wertefolgen gibt es
In welcher Variablen wird welche Folge gespeichert
Wann endet die Berechnung
n
i
sum
5
0
0
5
1
1
5
2
3
5
3
6
5
4
10
5
5
15
Schleifenende
Initialisierung:
Wie kommt
man zu Zeile 1
Schleifenkörper:
Wie kommt man
von Zeile zu Zeile
Schleifenende:
Bedingung mit
gestoppt wird
Seite 5
n
= 5
sum = 0
i
= 0
while ( i < n ) {
i = i+1
sum = sum + i
}
While-Schleife
Übung
Die Summe der ersten n natürlichen Zahlen kann nach einer Formel berechnet
werden:
n
∑ i = ½ n * (n+1)
i=1
➢
➢
➢
Schreiben Sie eine Funktion, die sumF(x), die die Summe der ersten x natürlichen
Zahlen nach dieser Formel berechnet.
Schreiben Sie eine Funktion sumW(x), die die Summe der ersten x natürlichen
Zahlen durch Aufsummieren berechnet.
Schreiben Sie eine Schleife in der die Summe der der ersten n Zahlen für
n = 1 · · · 100
jeweils mit beiden Funktionen berechnet und ausgegeben wird.
Seite 6
Do-While-Schleife
Schleife, Do-While-Schleife
Kontrolle am Ende eines Durchlaufs
int n = 5;
int sum = 0;
int i
= 0;
do {
i = i + 1;
sum = sum + i;
} while (i < n);
Der erste Durchlauf findet in
jedem Fall statt !
Seite 7
For-Schleife
For-Schleife
Die Schleife durchläuft eine Folge von Werten
Allgemeine Form
for ( Start-Anw; Bedingung; Inkrement-Anw )
Anweisung(-sfolge)
Beispiel
for ( int i = 0; i <= n; i=i+1 ) {
sum = sum + i;
}
Seite 8
For-Schleife
For-Schleife
Ausführung
for ( Start-Anw Bedingung; Inkrement-Anw )
Anweisung(-sfolge)
entspricht:
Start-Anw
while ( Bedingung ) {
Anweisung(-sfolge)
Inkrement-Anw
}
Beispiel
for ( int i = 0; i <= n; i=i+1 ) {
sum = sum + i;
}
Seite 9
≈
int i =
while (
sum
i =
}
0
i <= n ) {
= sum + i;
i + 1;
For-Schleife
Übung
Modifizieren Sie Ihr Programm zur Berechnung der Summe der ersten n
natürlichen Zahlen derart, dass nur For-Schleifen verwendet werden.
Seite 10
Schleife
Übung Schleifenkonstruktion
Berechne in einer Funktion den Wert
a = a0 + a1 + · · · an
mit
a0 = 0,
und
ai = ai-1 + c
für ein vorgegebenes n und c (Funktionsparameter).
Gehen Sie systematisch vor:
1. Berechnen Sie ein Beispiel „händisch“.
2. Welche Werte / Wertefolgen müssen berechnet werden?
3. In welchen Variablen werden diese abgespeichert?
4. Erstellen Sie eine Wertverlaufstabelle.
5. Konstruieren Sie die Schleife nach der Wertverlaufstabelle.
Seite 11
Schleife
Schleifenkontrolle
break - Anweisung
beendet die Schleife
continue -Anweisung
bricht den aktuellen Schleifendurchlauf ab:
weiter (continue !) mit dem nächsten Durchlauf
Seite 12
Schleife
Beispiel
Scanner scan = new Scanner(System.in);
int n = 0;
do {
System.out.println("Bitte positive Zahl, Abbruch mit 0");
n = scan.nextInt();
if (n < 0) continue;
if (n == 0) break;
int sum = 0;
int i
= 0;
while (i < n) {
i = i + 1;
sum = sum + i;
}
System.out.println("Summe 1 ... " + n + " = " + sum);
} while (true);
Seite 13
Rekursion
Seite 14
Rekursion
Rekursion
Ursprung
lat. recurrere ~ zurücklaufen
rekursive Definition
Definition mit Bezug auf sich selbst
Ein Konzept wird rekursiv definiert, wenn in der Definition des Konzepts
dieses selbst vorkommt.
Beispiel rekursiv definierter Algorithmus:
Gehe-zum-Erdgeschoss:
Bist Du im Erdgeschoss, dann bist du fertig,
Sonst: gehe ein Stockwerk tiefer und führe
dann den Algorithmus Gehe-zum-Erdgeschoss aus.
Das zu erklärende Konzept ist Gehe-zum-Erdgeschoss. In seiner Erklärung
(=Definition) kommt Gehe-zum-Erdgeschoss selbst vor.
Was passiert, wenn der Algorithmus
im Keller ausgeführt wird?
Seite 15
Rekursion
Beispiel rekursive Definition: Fakultätsfunktion n!
Das zu erklärende Konzept ist ! . In seiner Erklärung (=Definition) kommt !
selbst vor.
●
●
0! = 1
n! = (n-1)! * n
als Funktionsdefinition:
Das zu erklärende Konzept ist fak . In seiner Erklärung (=Definition) kommt
fak selbst vor.
●
●
fak(0) = 1
fak(n) = fak(n-1)*n
oder
●
1
n=0
fak(n-1)*n
sonst
fak(n) =
Seite 16
Rekursion
Rekursive Funktionsdefinition = (rekursiver) Algorithmus
Jede rekursiv definierte Funktion kann als
rekursiv definierter Algorithmus verstanden werden.
– Definition
der Funktion fak(n):
 fak(0) = 1
 fak(n) = fak(n-1) * n
– Algorithmus
zur Berechnung von fak(n):
 Falls n = 0 ~> Resultat = 1
 Sonst
1. Erzeuge Gehilfe fakn-1
2.Lasse Gehilfen berechnen fakn-1(n-1) ~> (n-1)!
3.nimm das Ergebnis (n-1)! des Gehilfen und
multipliziere es mit n ~> (n-1)!*n
Seite 17
Rekursion
Rekursion
indirekte rekursive Definition (indirekte Rekursion)
Definition mit indirektem Bezug auf sich selbst
Beispiel gerade / ungerade
●
●
●
●
gerade(0) = true
gerade(n) = ungerade(n-1)
0 ist gerade
n ist gerade, wenn n-1 ungerade ist
ungerade(0) = false
ungerade(n) = gerade(n-1)
0 ist nicht ungerade
n ist ungerade, wenn n-1 gerade ist
Seite 18
Rekursion
Rekursion in Programmiersprachen
Rekursion in Programmiersprachen
Rekursion ab ~ 1960 von allen (relevanten)
Programmiersprachen unterstützt
E.W. Dijkstra: Pinonier der
Informatik. Entwickelte u.a.
Verfahren zum Übersetzen u.
Ausführen rekursiver
Funktionen
Ab ~1970 als wichtige Kontrollstruktur allgemein
anerkannt und eingesetzt.
Rekursion in Java
Beispiel Fakultätsfunktion
package rekursion;
public class Fakultaet {
private static int fak(int x) {
if (x == 0) {
return 1;
} else {
return fak(x-1)*x;
}
}
n! = 1
falls n=0
(n-1)!*n falls n>0
undefiniert sonst
public static void main(String[] args) {
System.out.println(fak(5));
}
}
Seite 19
Übung: fak mit
bedingtem Ausdruck?
Rekursion
Beispiel
Die Summation 1 bis n
n
sumBis(n)
=∑ i
i=0
kann rekursiv definiert werden. Wie?
Seite 20
Rekursion und Iteration
int sumBisIterativ(int n) {
int sum = 0;
for ( i = 0; i <= n; i = i+1 ) {
sum = sum + i;
}
return sum;
}
Algorithmen, die mit Schleifen
statt Rekursion arbeiten, nennt
man iterativ.
int sumBisRekursiv(int n) {
return n == 0 ? 0 : sumBisRekursiv(n-1)+n;
}
Seite 21
Rekursion und Iteration
Beispiel : Berechnung der Exponentionfunktion / rekursiv
Exponentialfunktion
x
2
3
e =1 x x /2! x / 3!···
Welche Beziehung besteht zwischen den Summengliedern:
➢
Kann ein Summenglied aus seinem Vorgänger
berechnet werden? (Rekursion ?)
Seite 22
Rekursion und Iteration
Beispiel : Berechnung der Exponentionfunktion / rekursiv
Exponentialfunktion
x
2
3
e =1 x x /2! x / 3!···
Welche Beziehung besteht zwischen den Summengliedern:
➢
Kann ein Summenglied aus seinem Vorgänger
berechnet werden? (Rekursion ?)
Startwert =1
1∗x= x
x ∗x / 2=x 2 /2
x 2 / 2 ∗x /3=x 3 / 3 !
x 3 / 3! ∗x /4= x 4 / 4 !
· ··
(rekursive) Funktion ?
Seite 23
Rekursion und Iteration
Beispiel : Berechnung der Exponentionfunktion / rekursiv
Exponentialfunktion
x
2
3
e =1 x x /2! x / 3!···
Welche Beziehung besteht zwischen den Summengliedern:
➢
Kann ein Summenglied aus seinem Vorgänger
berechnet werden? (Rekursion ?)
Startwert =1
1∗x= x
x ∗x / 2=x 2 / 2
x 2 /2 ∗x / 3= x 3 / 3!
x 3 / 3! ∗x / 4=x 4 / 4 !
·· ·
s(x, 0) = 1
s(x, i) = s(x, i-1) * x/i
Java-Funktion zur rekursiven Berechnung des
i-ten Summanden?
Seite 24
Rekursion und Iteration
Beispiel : Berechnung der Exponentionfunktion / rekursiv
Exponentialfunktion
x
2
3
e =1 x x /2! x / 3!···
Welche Beziehung besteht zwischen den Summengliedern:
➢
Kann ein Summenglied aus seinem Vorgänger
berechnet werden? (Rekursion ?)
Startwert =1
1∗x= x
x ∗x / 2=x 2 / 2
x 2 /2 ∗x / 3= x 3 / 3!
x 3 / 3! ∗x / 4=x 4 / 4 !
·· ·
s(x, 0) = 1
s(x, i) = s(x, i-1) * x/i
double s(double x, int i) {
return i == 0 ? 1
: s(x,i-1) * x / i
}
e-Funktion ?
Seite 25
Rekursion und Iteration
Beispiel : Berechnung der Exponentionfunktion / iterativ
Exponentialfunktion
x
2
3
e =1 x x /2! x / 3!···
Welche Beziehung besteht zwischen den Summengliedern:
➢
Kann ein Summenglied aus seinem Vorgänger
berechnet werden? (Iteration ?)
Startwert =1
1∗x = x
x ∗x /2=x 2 / 2
2
3
x /2 ∗x / 3=x / 3 !
x 3 / 3! ∗x / 4= x 4 / 4 !
· ··
x
i
x
x
x
x
x
0
1
2
3
4
s
1
x
x*x/2
x*x*x/2*3
x*x*x*x/2*3*4
Vorwärtsberechnung:
Wertverlaufstabelle
···
Funktion zur iterativen Berechnung des i-ten
Summanden?
Seite 26
Rekursion und Iteration
Beispiel : Berechnung der Exponentionfunktion / iterativ
Exponentialfunktion
x
2
3
e =1 x x /2! x / 3!···
Welche Beziehung besteht zwischen den Summengliedern:
➢
Kann ein Summenglied aus seinem Vorgänger
berechnet werden? (Iteration ?)
x
i
x
x
x
x
x
0
1
2
3
4
s
double s(x,j) {
double s = 1;
double i = 0;
while (i < j) {
i = i+1;
s = s*x/i;
}
return s
}
1
x
x*x/2
x*x*x/2*3
x*x*x*x/2*3*4
···
e-Funktion ?
Seite 27
Rekursion und Iteration
Übung
Berechnen Sie die Exponentialfunktion
e x=1xx 2 /2 ! x3 /3 !· ··
in einer (einzigen) Funktion, die nur eine Schleife verwendet
Konstruieren Sie Schleife aus einer Wertverlaufstabelle, in der auch die
Summe, d.h. der angestrebte Wert berechnet wird.
x
i
x
x
x
x
x
0
1
2
3
4
s
1
x
x*x/2
x*x*x/2*3
x*x*x*x/2*3*4
e^x
1
1+x
?
?
?
···
Seite 28
Schleifeninvariante
Schleifeninvariante
Die Schleifeninvariante ist eine
– wesentliche und
– zu Beginn jedes Schleifendurchlaufs gültige Aussage
– über Variablen die in einer Schleife vorkommen.
Die Schleifeninvariante beschreibt
– in Form eines Kommentars,
– etwas Wichtiges,
das sich in der Schleife nicht ändert.
Typischerweise handelt es sich um eine Beziehung zwischen Variablenwerten.
Seite 29
Schleifeninvariante
Beispiel:
private static int fakIter(int x) {
int n = 0;
int f = 1;
while (n < x) { // INV f == n!
n = n+1;
f = f*n;
}
return f;
}
Schleifeninvariante:
der Wert von f ist immer
(genauer: immer vor dem Test der Bedingung)
gleich der Fakultät des Wertes von n.
Seite 30
Schleifeninvariante
Die Schleifeninvariante
– Kommentiert Dinge die nicht offensichtlich sind
– Bringt die Idee der Schleife zum Ausdruck
private static int fakIter(int x) {
int n = 0;
int f = 1;
while (n < x) { // INV f == n!
n = n+1; // n wird erhöht
f = f*n; // f wird mit n multipliziert
}
return f;
}
n ist die Folge der natürlichen Zahlen:
offensichtlich erkennbar im Code, Kommentar unsinnig.
f wird auf-multipliziert:
offensichtlich erkennbar im Code, Kommentar unsinnig.
Seite 31
In der
Variablen f multipliziere
ich die Folge der natürlichen
Zahlen auf, die ich in n bilde.
Dann ist da immer
die Fakultät bis n drin.
Wenn dann n = x ist, dann
bin ich fertig
Schleifeninvariante
Die Schleifeninvariante
– hilft bei Argumentationen zur Korrektheit
private static int fakIter(int x) {
int n = 0;
int f = 1;
while (n < x) { // INV f == n!
n = n+1;
f = f*n;
}
// f == n! && !(n < x)
// x == n && f == n! => f == x!
return f;
}
Am Ende der Schleife gilt die Invariante und die
Negation der Schleifenbedingung.
Seite 32
Test
Schleifeninvariante
– Test mit assert
package fakultaet;
public class Fakultaet {
private static int fak(int x) {
if (x == 0) { return 1;
} else {
return fak(x-1)*x;
}
}
assert: -ea nicht vergessen!
private static int fakIter(int x) {
int n = 0;
int f = 1;
assert(f == fak(n));
while (n < x) { // INV f == fak(n)
assert(f == fak(n));
n = n+1;
f = f*n;
}
assert(f == fak(x));
return f;
}
Rekursive Variante als
(offensichtlich korrekte)
Referenz
}
Seite 33
Schleifeninvariante
Beispiel GGT
public static int ggt(int a, int b){
int a0 = a; // „Geistervariable“; Werte van a und b zur Fomulierung
int b0 = b; // der Invariante festhalten
while (a!=b) { // INV ggt(a0,b0) == ggt(a,b)
if (a>b) {
a = a - b;
} else {
b = b -a;
}
}
return a;
}
Invariante erklärt das Funktionieren des Codes:
Die Schleife ist korrekt denn
ggt(a,b) = ggt(max(a,b)-min(a,b), min(a,b))
(Mathematik!)
Seite 34
Rekursion und Iteration
Schleifeninvariante
in der Programmentwicklung
x
2
3
e =1xx /2 ! x /3 !· ··
x
i
x
x
x
x
x
0
1
2
3
4
s
1
x
x*x/2
x*x*x/2*3
x*x*x*x/2*3*4
e
1
1+x
1+x+x*x/2
1+x+x*x/2+x*x*x/2*3
1+x+x*x/2+x*x*x/2*3+ x*x*x*x/2*3*4
···
Zeilen-Invariante: Welche wichtige
Beziehung besteht in jeder Zeile zwischen
den Werten der Spalten?
Seite 35
Rekursion und Iteration
Schleifeninvariante
in der Programmentwicklung
x
2
3
e =1xx /2 ! x /3 !· ··
x
i
x
x
x
x
x
0
1
2
3
4
s
1
x
x*x/2
x*x*x/2*3
x*x*x*x/2*3*4
e
public static double eHoch(double x){
double s = 1.0;
double e = 1.0;
int i = 0;
while (i<50) { //INV s=x^i/i!,
// e=SUM(j<=i) x^j/j!
i= i+1;
s = s*x/(double)i;
e = e + s;
}
return e;
}
Die Idee der
1
Tabelle / Schleife
1+x
1+x+x*x/2
1+x+x*x/2+x*x*x/2*3
1+x+x*x/2+x*x*x/2*3+ x*x*x*x/2*3*4
···
Zeilen-Invariante: Welche wichtige
i
s=x /i!
Beziehung besteht in jeder Zeile zwischen
den Werten der Spalten?
Seite 36
i
j
e=∑ x / j !
j =0
Herunterladen