Lösung - Heinz Nixdorf Institut

Werbung
HEINZ NIXDORF INSTITUT
Universität Paderborn
Technische Informatik für Ingenieure – WS 2010/2011
Musterlösung Übungsblatt Nr. 12
24. Januar 2011
Übungsgruppenleiter:
Matthias Fischer
Mouns Almarrani
Rafał Dorociak
Michael Feldmann
Thomas Gewering
Benjamin Koch
Dominik Lüke
Alexander Teetz
Simon Titz
Simon Oberthür
Seite 1(4)
Aufgabe 1:
(Rekursion)
a)
Erstellen Sie ein Java-Programm, welches die Ackermann-Funktion rekursiv berechnet.
Die Ackermann-Funktion sei wie folgt rekursiv definiert:
ackermann(0, m)
=
m+1
ackermann(n, 0)
=
ackermann(n - 1, 1)
ackermann(n, m)
=
ackermann(n - 1, ackermann(n, m - 1))
Lösung:
„Die Ackermann-Funktion ist ein prominentes Beispiel für eine rekursive Funktion, die jetzt - und
noch die nächsten Jahrzehnte - Informatiker im Studium beschäftigt.
Sie ist nach F. Wilhelm Ackermann (1886-1962) benannt. Viele Funktionen der mathematischen
Praxis sind primitiv rekursiv, und David Hilbert stellte 1926 die Frage, ob alle Funktionen, deren
Argumente und Werte natürliche Zahlen sind, primitiv rekursiv sind. Die Ackermann-Funktion
steigt sehr stark an und ist für Theoretiker ein Beispiel dafür, dass es berechenbare Funktionen
gibt, die aber nicht primitiv rekursiv sind. Im Jahre 1928 zeigte Ackermann dies an einem Beispiel: der Ackermann-Funktion.6 Sie wächst stärker als es Substitution und Rekursion ermöglichen und nur für kleine Argumente lassen sich die Funktionswerte noch ohne Rekursion berechnen. Darin bestand auch die Beweisidee von Ackermann, eine Funktion zu definieren, die
schneller
wächst
als
alle
primitiv
rekursiven
Funktionen.“
[http://www.tutego.com/java/articles/Ackermann-Funktion.html]
public class Ackermann {
public static int ackermann(int n, int m) {
Out.println( "Ackermann(" + n + "," + m + ")" );
if (n == 0) return( m+1 );
if (m == 0) return( ackermann(n-1,1) );
return ackermann( n-1, ackermann( n, m-1 ) );
}
public static void main (String[] args) {
Out.print("Geben Sie zwei natuerliche Zahlen ein: ");
int n = In.readInt();
int m = In.readInt();
int erg = ackermann(n,m);
Out.println( "Resultat: Ackermann("+n+","+m+")=" + erg);
}
}
Technische Informatik für Ingenieure
Seite 2(4)
Für große Zahlen übersteigt die Funktion aber schnell alle Berechnungsmöglichkeiten. Zum
Vergleich: Die Ackermannfunktion berechnet beim Zahlenpaar (4,7) etwa 0,2*10^20. Unter der
hier verwendeten Definition der Ackermannfunktion ergibt sich folgende Tabelle:
A(x,y)
y=0
y=1
y=2
y=3
y=4
y=5
x=0
1
2
3
4
5
6
x=1
2
3
4
5
6
7
x=2
3
5
7
9
11
13
x=3
5
13
29
61
125
253
x=4
13
65533
265536-3
2265536-3
a(3,a(4,4))
x=5
65533
a(4,65533)
a(4,
a(4,65533))
a(4,a(5,2))
a(3,
2265536-3)
a(4,a(5,3))
b)
Geben Sie die Schritte der Rekursion für den Aufruf ackermann(1,2) an.
ackermann(1,2)
4
ackermann( 0, ackermann(1,1) )
3
ackermann( 0, ackermann(1,0) )
2
ackermann(0,1)
a(4,a(5,4))
Technische Informatik für Ingenieure
Aufgabe 2:
Seite 3(4)
(Rekursion)
Schreiben Sie ein Programm, das zwei natürliche Zahlen n und k einließt und rekursiv den
Binomialkoeffizienten „n über k” gemäß der folgenden Definition berechnet und ausgibt:
Kleine Illustration: Der Binomialkoeffizient gibt die Anzahl der Möglichkeiten an, die sich ergeben, wenn man aus einer Menge von n Elementen k Elemente ohne Zurücklegen herausnimmt. Der Binomialkoeffizient aus 49 „über“ 6 beispielsweise ergibt 13 983 816. Die Wahrscheinlichkeit beim Lotto 6 Richtige zu haben ist also 1 : 13 983 816. Der Binomialkoeffizient
von 4 über 3 berechnet sich gemäß der obigen Formel folgendermaßen:
Lösung:
public class Binom
{
static int binom(int n, int k)
{
if ( k == 0 || k == n )
return 1;
else
return binom(n-1, k-1) + binom(n-1,k);
}
public static void main(String[] args)
{
Out.print("Bitte geben Sie eine natürliche Zahl ein: ");
int n = In.readInt();
Out.print("Bitte geben Sie eine natürliche Zahl ein: ");
int k = In.readInt();
if ( n < 0 || k < 0 )
{
Out.print("Es sind nur natürliche Zahlen erlaubt! ");
return;
}
int erg = binom(n,k);
Out.print(n + " über " + k + " beträgt: " + erg);
}
}
Technische Informatik für Ingenieure
Aufgabe 3:
Seite 4(4)
(Rekursion)
Der größte gemeinsame Teiler zweier natürlicher Zahlen n und m, kann nach folgender
Definition rekursiv berechnet werden:
Schreiben Sie ein Programm, das zwei natürliche Zahlen n und m einließt und rekursiv den
größten gemeinsamen Teiler berechnet und ausgibt.
Lösung:
public class GGT
{
public static void main(String[] args)
{
Out.print("Bitte geben Sie eine natürliche Zahl ein: ");
int n = In.readInt();
Out.print("Bitte geben Sie eine natürliche Zahl ein: ");
int m = In.readInt();
if ( n < 0 || m < 0 )
{
Out.print("Es sind nur natürliche Zahlen erlaubt! ");
return;
}
int erg = ggT(n,m);
Out.print("ggT von " + n + " und " + m + " ist: " + erg);
}
public static int ggT(int n, int m)
{
if ( n == m )
return n;
else if ( n > m )
return ggT( n-m, m );
else
return ggT( n, m-n );
}
}
Herunterladen