7 Punkte

Werbung
Übung zur Vorlesung Einführung in die Programmierung“, WS 14/15
”
Übungsleiter: Sebastian Ebers <[email protected]>
Aufgabenblatt 4
https://moodle.uni-luebeck.de/mod/assign/view.php?id=11542
Abgabe: 15.12.2014, vor der Vorlesung / Großübung (10:00 Uhr, AM 1)
Max. Punktzahl: 76
Theoretischer Teil (für die Bearbeitung zu Hause)
Aufgabe 4.1: Iteration und Rekursion (7 Punkte)
a) Gegeben sei folgendes Programm:
1
2
3
4
5
6
7
8
fun sum(arr[1..n] : int) : int
{{
var s:=0;
for i:=1 to n do
s := s+arr[i];
od;
return s;
}}
Formen Sie den gegebenen iterativen Algorithmus in eine rekursive Funktion in
Pseudocode um. Die Methodensignatur darf hierbei verändert werden.
(3 P.)
1
b) Gegeben sei folgendes Programm:
1
2
3
4
5
6
7
8
9
10
fun c(arr[1..n] : int, elem : int, index : int) : bool
{{
if index < 1 or index > n then
return false;
else if arr[index] = elem then
return true;
else
return c(arr, elem, index+1);
fi;
}}
i) Was berechnet das Programm?
(1 P.)
ii) Formen Sie den gegebenen rekursiven Algorithmus in eine iterative Funktion in Pseudocode um.
(3 P.)
Aufgabe 4.2: Schleifen (9 Punkte)
Die Schleifenarten for, while und do-while besitzen die selbe Ausdrucksstärke.
So lassen sich Programme, die eine Schleifenart verwenden, in ein semantisch äquivalentes Programm umschreiben, welches eine andere Schleifenart verwendet.
Anstatt der in der Vorlesung vorgestellten Notation für die for-Schleife (for i:=
1 to n do α od;), soll im Folgenden die (aus C++ und Java bekannte) Notation
gelten: for ( α; β ; γ ; ) { δ ; }, wobei α die Initialisierung der Schleife ist,
β die Schleifenbedingung, γ die Modifikation und δ eine oder mehrere Anweisungen.
Formen Sie die folgenden Schleifenarten um in ein semantisch äquivalentes Programm
um. Nutzen Sie dabei immer alle Anweisungen α, β, γ, δ.
a) Formen Sie folgendes Programm in ein Programm mit while-Schleife um:
for ( α; β ; γ ; ) { δ ; }
(3 P.)
b) Formen Sie folgendes Programm in ein Programm mit while-Schleife um:
α ; do { δ ; γ ;} while(β)
(3 P.)
c) Formen Sie folgendes Programm in ein Programm mit do-while-Schleife um:
for ( α; β ; γ ; ) { δ ; }
(3 P.)
2
Aufgabe 4.3: Imperative Algorithmen (7 Punkte)
Gegeben sei folgendes Programm:
1
2
3
4
5
6
7
PRG:
var x,y,t : int;
intput x,y;
t := y;
y := x;
x := t;
output x,y;
a) Was berechnet das Programm?
(1 P.)
b) Welche Signatur besitzt PRG ?
(2 P.)
c) Werten Sie PRG mit Hilfe der in der Vorlesung vorgestellten Semantikfunktion
[[]] für die Eingabe x = 12 und y = 24 aus.
(4 P.)
3
C++-Kurs (für die betreute Rechnerzeit)
Aufgabe 4.4: Methodenaufrufe (18 Punkte)
Gegeben sei folgendes Programm:
1
2
#include<stdlib.h>
#include <iostream>
3
4
using namespace std;
5
6
7
8
9
10
11
void summiere(short a, int b) {
cout << "Methode ’summiere’: " << endl;
cout << "a: " << a << endl;
cout << "b: " << b << endl;
cout << "Ergebnis: " << (a + b) << endl;
}
12
13
14
15
16
17
18
void addiere(int summandA, short summandB) {
cout << "Methode ’addiere’:" << endl;
cout << "SummandA: " << summandA << endl;
cout << "SummandB: " << summandB << endl;
cout << "Ergebnis: " << (summandA + summandB) << endl;
}
19
20
21
22
23
24
25
void subtrahiere(int a, short b) {
cout << "Methode ’subtrahiere’:" << endl;
cout << "’a’: " << a << endl;
cout << "’b’: " << b << endl;
cout << "Ergebnis: " << (a - b) << endl;
}
26
27
28
29
30
31
32
void dividiere(double dividend, double divisor) {
cout << "Methode ’dividiere’:" << endl;
cout << "’Dividend’: " << dividend << endl;
cout << "’Divisor’: " << divisor << endl;
cout << "Ergebnis: " << (dividend / divisor) << endl;
}
33
34
35
36
37
38
39
void multipliziere(double mult1, int mult2) {
cout << "Methode ’multipliziere’:" << endl;
cout << "’Multiplikator’: " << mult2 << endl;
cout << "’Multiplikand’: " << mult1 << endl;
cout << "Ergebnis: " << (mult2 * mult2) << endl;
}
40
41
int main(int lenArgs, char *args[]) {
42
43
44
45
46
short a = 3;
int b = 5;
summiere(a, b);
addiere(b, a);
47
48
49
50
short subtrahend = 2;
int minuend = 4;
subtrahiere(minuend, subtrahend);
51
52
53
54
double dividend = 7;
double divisor = 14.0;
dividiere(divisor, dividend);
55
56
multipliziere(7.5, 4);
57
58
59
60
61
cout << "Methode ’main’: ";
cout << a << "/" << b << " = " << (b / a)
<< endl;
}
4
a) Geben Sie an, was auf der Konsole ausgegeben wird und welchen Typ die verwendeten Variablen haben.
b) Nennen Sie die Besonderheiten oder Probleme, die sich beim Aufruf der Methode
dividiere ergeben. Liefert sie das vom Aufrufer erwartete Ergebnis?
(1 P.)
c) Warum kann das Problem, das sich bei dividiere ergibt, bei subtrahiere
nicht auftreten?
(1 P.)
Aufgabe 4.5: Funktionen (14 Punkte)
a) Eine mögliche Lösung für die Aufgabe Schleifen vom letzten Übungsblatt könnte
wie folgt aussehen:
1
2
3
4
// Schleifen.cpp
#include<stdlib.h>
#include <iostream>
using namespace std;
5
6
7
8
9
10
11
12
13
14
15
int main(int lenArgs, char *args[])
{
// Aufgabe a)
int zahl = atoi(args[1]);
long ergebnis = 1;
for (int i = 1; i <= zahl; i++) {
ergebnis = ergebnis * i;
}
cout << "Fakultaet von: " << args[1] << " ist " << ergebnis
<< endl;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Aufgabe b)
int zahl1 = atoi(args[2]);
int zahl2 = atoi(args[3]);
int x = zahl1;
int y = zahl2;
while (x != y) {
if (x > y) {
x = x - y;
} else {
y = y - x;
}
}
cout << "ggT von " << zahl1 << " und "
<< zahl2 << " ist " << x << endl;
}
Da die Main-Methode mit den Berechnungen der beiden Algorithmen etwas
unübersichtlich geworden ist, lagern wir die Berechnungen der Algorithmen in
zwei Methoden aus, in denen die Berechnung durchgeführt und das Ergebnis
zurückgegeben wird. Erzeugen Sie zunächst ein neues Programm mit dem Namen Funktionen.cpp und speichern Sie die ersten drei Übergabeparameter
ähnlich wie oben.
5
(1 P.)
b) Lagern Sie die Berechnung der Fakultät in eine eigene Methode mit folgender
Signatur aus:
static long fakultaet(int n)
Die Methode berechnet die Fakultät des Übergabeparameters n und gibt das
Ergebnis zurück an die aufrufende Methode.
(2 P.)
c) Lagern Sie die Berechnung des größten gemeinsamen Teilers in eine eigene Methode mit folgender Signatur aus:
static int ggT(int x, int y)
Hier wird der größte gemeinsame Teiler von x und y berechnet und an die
aufrufende Methode zurückgeliefert.
(2 P.)
d) Rufen Sie aus der Main-Methode heraus die beiden Funktionen
fakultaet(int n) und ggT(int x, int y) auf,
berechnen Sie für den ersten Übergabeparameter die Fakultät, danach den GGT
von Parameter zwei und drei. Geben Sie jeweils die Rückgaben der Methoden
aus.
(3 P.)
e) Angenommen, Sie wollen eine Zahlenkombination für einen Tresor auswählen.
Es stehen 20 Zahlen zur Verfügung und Sie benötigen drei verschiedene Zahlen
für die Kombination. Dann gibt es P (20, 3) Möglichkeiten für diese Zahlenkombination, wobei P definiert wird durch die Formel
P (a, b) = (a!)/(a − b)!
Benutzen Sie die von Ihnen implementierte Methode fakultaet(int n), um
die beschriebene Formel für die Werte a = 20 und b = 3 in der Main-Methode
zu berechnen.
(3 P.)
f) Lagern Sie nun auch diese Formel in eine Methode mit dem Namen
tresorKombinationen aus. Die Methode erhält die beiden Werte a und b
als Übergabewerte und liefert als Ergebnis die Anzahl der möglichen Kombinationen zurück. Überlegen Sie sich hierzu zunächst, wie die Übergabeparameter
und der Rückgabewert aussehen müssen, damit der Zahlenraum zur Übergabe
der Werte ausreicht und begründen Sie Ihre Wahl kurz. Rufen Sie die Funktion
tresorKombinationen aus der Main-Methode mit den Werten a = 20 und
b = 3 auf.
(3 P.)
6
Aufgabe 4.6: Iteration und Rekursion (11 Punkte)
Die folgenden Teilaufgaben sollen in die rekursive Programmierung einführen und
den Unterschied zwischen iterativer und rekursiver Programmierung verdeutlichen.
Erstellen Sie dazu ein Programm Rekursion.cpp. Als Lösung ist der gesamte kommentierte Code abzugeben. Es ist nicht nötig, einzelne Abgaben zu den jeweiligen
Aufgabenteilen anzufertigen.
a) Fakultät
In der Aufgabe Funktionen haben Sie eine iterative Berechnung der Fakultät
implementiert:
n
Y
n! = 1 · 2 · 3 · ... · n =
k
k=1
Diese Art der Programmierung durch Wiederholung der gleichen Anweisung
(beispielsweise in einer FOR-Schleife) wird als iterativ (lat. iterare, wiederholen)
bezeichnet. Eine andere Möglichkeit ist die rekursive (lat. recurrere, zurücklaufen) Lösung. Dabei wird innerhalb der Methode die Methode selbst aufgerufen.
(i) Implementieren Sie die Methode fakultaet rekursiv. Verwenden Sie dazu die rekursive Definition der Fakultät:
1 falls n = 0
n! =
n · (n − 1)! falls n > 0
Hinweis: Fakultäten für negative Zahlen sind nicht definiert.
(2 P.)
(ii) Schreiben Sie ein Hauptprogramm (es genügt auch eine Main-Methode
innerhalb der im vorherigen Teil erstellten Klasse, das die Ergebnisse der
Rekursion von n = 1 bis n = 12 ausgibt.
(1 P.)
7
b) Kaninchen
Auf einer Insel setzt ein geschäftstüchtiger Kaninchenzüchter ein junges Kaninchenpaar aus. Die Tiere sind nach 2 Monaten geschlechtsreif und bekommen
dann jeden Monat ein Paar als Nachwuchs. Im dritten Monat gibt es also ein
neues Paar, welches im 5. Monat selbst wieder Nachwuchs bekommt usw..
Dabei sei vorausgesetzt, dass immer genug Futter vorhanden ist, der Nachwuchs
immer ein Männchen-Weibchen-Paar ist, keine Fressfeinde auf der Insel leben
und die Kaninchen unsterblich sind.
(i) Schreiben Sie ein rekursives Programm, welches die Anzahl der Kaninchenpaare im Monat n ausgibt. Die Populationsstärke wird durch die
Fibonacci-Folge f1 , f2 , ... mit der rekursiven Bildungsvorschrift
fn =


0 falls n = 0
1 falls n = 1

fn−1 + fn−2 falls n ≥ 2
definiert.
Erstellen Sie dazu die Methode fibonacci, welche die Anzahl der Paare
im n-ten Monat ausgibt.
Erweitern Sie Ihr Hauptprogramm so, dass die Anzahl der Paare der Monate 1 bis 12 und außerdem die Anzahl der Paare nach 2, 3, 4 und 5 Jahren
am Bildschirm angezeigt werden.
(3 P.)
(ii) Was fällt Ihnen bei der (Dauer der) Berechnung der letzten beiden Werte
auf?
(1 P.)
(iii) Warum tritt dieser Effekt auf?
(2 P.)
(iv) Implementieren Sie die Rekursion in einer neuen Methode so, dass dieser
Effekt nicht auftritt!
(2 P.)
Hinweis: Die Lösung der Teilaufgabe (iv) ist deutlich schwerer, als die
Anzahl der Punkte vermuten lässt.
8
Aufgabe 4.7: Gültigkeitsbereiche (10 Punkte)
Analysieren Sie das folgende Programm und achten Sie dabei insbesondere auf die verschiedenen Gültigkeitsbereiche der Klasse, der Methoden und der lokalen Variablen.
Was wird auf der Konsole ausgegeben, wenn das Programm mit dem Übergabeparameter 23 aufgerufen wird? Begründen Sie Ihre jeweilige Antwort kurz.
(10 P.)
1
2
3
4
// Gueltigkeitsbereiche.cpp
#include<stdlib.h>
#include<iostream>
using namespace std;
5
6
7
8
9
10
11
12
13
14
class Gueltigkeitsbereiche {
public:
Gueltigkeitsbereiche();
Gueltigkeitsbereiche(int, char**);
static int i;
static void classMethod();
int memberMethod();
};
int Gueltigkeitsbereiche::i = 10;
15
16
17
18
19
20
21
22
23
24
Gueltigkeitsbereiche::Gueltigkeitsbereiche
(int len, char **args) {
i = atoi(args[1]);
cout << "b) i = " << i << endl;
int i = 6;
cout << "c) i = " << i << endl;
classMethod();
cout << "f) i = " << i << endl;
}
25
26
27
28
29
30
void Gueltigkeitsbereiche::classMethod(){
cout << "d) i = " << i << endl;
int i = 42;
cout << "e) i = " << i << endl;
}
31
32
33
34
35
36
37
38
39
40
41
int Gueltigkeitsbereiche::memberMethod(){
int j = 88;
{
j = 5;
cout << "g) i = " << ++i << endl;
cout << "h) j = " << j << endl;
}
cout << "i) i = " << i << endl;
return j;
}
42
43
44
45
46
47
48
int main(int len, char **args) {
cout << "a) i = " << Gueltigkeitsbereiche::i << endl;
Gueltigkeitsbereiche *gb = new Gueltigkeitsbereiche(len, args);
cout << "j) j = " << gb->memberMethod() << endl;
return 0;
}
9
Herunterladen