Informatik 1 (251-0832-00) D-MAVT F2011 Rekursion, Signaturen

Werbung
Informatik 1 (251-0832-00)
D-MAVT
F2011
Rekursion,
Signaturen
Yves Brise
20110420 - Übungsstunde 8
Nachbesprechung Blatt 5 & 6
Blatt 5
• Sortieren
• Pseudocode
• Vektoren
• Verschlüsselung
Blatt 6
• Zeiger, structs
• Listen
• Niederschlagsanalyse (Vorsicht int-Division)
Yves Brise
20110420 - Übungsstunde 8
Initialisierung Dynamisches Feld
Ein dynamisches Feld kann nicht mit geschwungenen Klammern
initialisiert werden! Verwende direkten Elementzugriff, oder
Konstruktoren.
struct foo {
int a, b;
};
int main() {
foo* test = new foo[3] = {{0,1},{0,2},{0,3}};
delete[] test;
return 0;
}
test.cpp:6: error: expected primary-expression before ‘{’ token
Yves Brise
20110420 - Übungsstunde 8
Initialisierung Dynamisches Feld
struct foo {
int a, b;
};
int main() {
foo* test = new foo[3];
test[0] = {0,1};
test[1] = {0,2};
test[2] = {0,3};
delete[] test;
return 0;
}
test.cpp:7: error: expected primary-expression before ‘{’ token
Yves Brise
20110420 - Übungsstunde 8
Initialisierung Dynamisches Feld
Direkter Elementzugriff
struct foo {
int a, b;
};
int main() {
foo* test = new foo[3];
test[0].a = 0; test[0].b = 1;
test[1].a = 0; test[1].b = 2;
test[2].a = 0; test[2].b = 3;
delete[] test;
return 0;
}
OK! Aber recht umständlich...
Yves Brise
20110420 - Übungsstunde 8
Initialisierung Dynamisches Feld
Direkter Elementzugriff
struct foo {
foo () {this->a = 0; this->b = 0;}
foo (int a, int b) {
this->a = a; this->b = b;
}
int a, b;
};
int main() {
foo* test = new foo[3];
Sehr komfortabel, vor allem
wenn die Datentypen
komplizierter werden.
test[0] = foo(0,1);
test[1] = foo(0,2);
test[2] = foo(0,3);
delete[] test;
return 0;
}
Yves Brise
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 1
Fibonacci Zahlen
Teilaufgabe a)
Definition
Berechnung

 0,
1,
fib(n) :=

fib(n − 1) + fib(n − 2),
if n = 0,
if n = 1,
if n ≥ 2
fib(2) = fib(1) + fib(0)
= 1+0
= 1
Teilaufgabe b)
Schaut euch die Auwertung aus a) einmal genau an...
Yves Brise
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 2
Labyrinth
Finden Sie einen Weg durch das Labyrith! Darstellung als char Feld, wobei X für
Hindernis, S für Startpunkt, Z für Ziel und die Zeichen >,<,^,v für rechts, links, oben
und unten steht.
Anfangssituation
Weg gefunden!
Yves Brise
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 2
Das Framework
Sie müssen nur die Datei labyrinth.cpp bearbeiten. Zusätzlich enthält das
Verzeichnis die Datei labyrinth.map, die Karte des Labyrinths codiert.
int loadLabyrinth(char *filename);
void printLabyrinth();
int main(int argc, char* argv[]) {
if (argc == 2) {
if (!loadLabyrinth(argv[1])) {
printLabyrinth();
resetLabyrinth();
}
}
return 0;
}
Yves Brise
Labyrith laden und ausgeben mit
Kommandozeilenparameter.
Alterntiv kann auch
“labyrinth.map” als
Argument an
loadLabyrinth übergeben
werden.
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 2
Die Datenstruktur
struct tLab {
// die wirkliche groesse des Labyrinths
// diese Zahlen werden aus dem Labyrinth-File eingelesen
int size_x;
int size_y;
// labyrinthOriginal enthaelt die original zeichen aus dem
// labyrinth file. Es wird durch resetLabyrinth() in die
// oeffentliche labyrinth-variable kopiert
// das labyrinthOriginal hat vertauschte X und Y coordinaten!
// dies macht das Einlesen einfacher
char labyrinth_original[80][80];
// die "gebrauchs-version" des labyrinths. Wenn
// zeichen geschrieben werden, wird diese Version veraendert
char labyrinth[80][80];
} lab;
Yves Brise
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 2
Zeichen schreiben/lesen
char zeichenAnPosition(int x, int y) {
return lab.labyrinth[x][y];
}
void setzeZeichenAnPosition(char zeichen, int x, int y) {
lab.labyrinth[x][y] = zeichen;
}
if (zeichenAnPosition(x,y) == 'X') {...}
setzeZeichenAnPosition('S', x, y);
Es wird nicht überprüft, ob die Operationen erlaubt sind. Das ist ihre Aufgabe.
Zum Beispiel soll das schreiben nur in leere Felder möglich sein.
Yves Brise
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 2
Die rekursive Lösung
bool sucheWeg(int sx, int sy, int zx, int zy)
{
// wir sind auf dem ziel gefunden
if (sx == zx && sy == zy) {
return true;
}
}
Yves Brise
• Wenn das Startfeld nicht
• Danach versuchen wir alle 4
Himmelsrichtungen.
// versuche Schritt nach rechts
setzeZeichenAnPosition('>', sx, sy);
if (sucheWeg(sx+1, sy , zx, zy)) return true;
// nicht erfolgreich von diesem Feld aus
setzeZeichenAnPosition('.', sx, sy); //
return false;
sind, können wir true
zurück geben.
leer ist, können wir false
zurückgeben.
// Diese Feld ist nicht leer.
// Hier geht es nicht weiter.
if (zeichenAnPosition(sx, sy) != ' ') {
return false;
}
// versuche Schritt nach links
// versuche Schritt nach unten
// versuche Schritt nach oben
• Wenn wir schon am Ziel
• Wichtig: Markiere erfolglose
Felder mit ’.’ oder
ähnlich, damit von da aus
nicht mehr gesucht wird.
• Auch wichtig: Sie können
annehmen, dass das
Labyrinth begrenzt ist mir
’X’.
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 3
Telefonbuch
int main()
{
eintrag * buch = 0; !
• Die main Funktion hat nur
// Erstelle leeres Telefonbuch
// Ermoeglicht dem Benutzer die naechste Aktion zu waehlen
int wahl = 1;
while (wahl != 0)
{
// Erleutere die Wahlmoeglichkeit
cout << "Was moechten Sie als naechstes tun?" << endl;
cout << "0: Programmende" << endl;
cout << "1: Eintrag erstellen" << endl;
cout << "2: Telefonbuch ausgabe" << endl;
cout << "3: Eintrag loeschen" << endl << endl;
cin >> wahl;
cin.ignore();
// Rufe je nach Wahl die richtige Funktion auf
switch (wahl)
{
case 0:
deleteBuch(buch);
break;
case 1:
addEintrag(buch);
break;
case 2:
printBuch(buch);
break;
case 3:
deleteEintrag(buch); break;
default: cout << "keine gueltige Angabe" << endl;
}
}
zum Zweck, den
Programmablauf zu
bestimmen.
• Die eigentliche
Funktionalität ist in die
Fuktionen deleteBuch,
addEintrag,
printBuch,
deleteEintrag
ausgelagert
}
return 0;
Yves Brise
20110420 - Übungsstunde 8
Blatt 8, Aufgabe 3
void
void
void
void
• Man beachte die Signatur
addEintrag(eintrag * &node);
deleteBuch(eintrag * &node);
printBuch(eintrag * node);
deleteEintrag(eintrag * &node);
mit Parameter Typ
eintrag * &
• Traversieren der Liste
notwendig
void deleteBuch(eintrag * &node)
{
eintrag * temp;
// Gehe durch die verkettete Liste und loesche jeden
Eintrag
while (node != 0)
{
temp = node;
node = node->next;
delete temp;
}
}
Yves Brise
• Nicht vergessen, den
Speicherplatz wieder
freizugeben.
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 4
Turtle Graphics
Siehe Demo!
Yves Brise
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5
Raytracing
Bildebene und
Objekte werden in
einer 3D Darstellung
modelliert.Vom
Augpunkt werden
dann die
Schnittpunkte vieler
Halbgeraden
berechnet.
Raytracing findet prominente Anwendung
in der 3D Computergraphik.
Yves Brise
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5
Das Framework
Sie müssen nur die Datei main.cpp aus dem Ordner framework
bearbeiten. Die Datei framework7.zip auf der Kurshomepage
enthält alles, was sie brauchen.Wenn Sie alles richtig gemacht haben,
dann schreibt das Programm eine Datei out.ppm. Dies ist eine
Bilddatei.
Sie können die .ppm Dateien mit Gimp
(Windows, Linux) oder ToyViewer (OS X)
anschauen.
Datenstruktur für Vektoren, Farben und Strahlen
typedef float[3] Vector3f;
typedef Vector3f color_rgb;
Yves Brise
struct ray {
Vector3f p; // Punkt
Vector3f d; // Richtung
};
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5
/******************************************************************************
* Funktion write_picture(color_rgb( )
*
*
Schreibt ein Bild(Array aus Farben) in out.ppm im PPM-Format
*
* Eingabeargumente: Array pic, das aus Elementen mit 3 Farben (RGB) besteht *
* Rueckgabewerte: kein3e
*
******************************************************************************/
void write_picture(color_rgb * pic);
pic ist ein Zeiger auf ein Feld, welches das Bild darstellt (kann man
eindimensional oder mehrdimensional machen).
/******************************************************************************
* Funktion generate_ray()
*
*
Generiert die den Strahl fuer den Pixel (x,y)
*
* Eingabeargumente: Koordinaten x, y. Kameramodel model
*
* Rueckgabewerte: Strahl welcher durch den Pixel verlaeuft
*
******************************************************************************/
ray generate_ray(int x, int y, camera_model model);
Rückgabewert ist eine Instanz von struct ray.
Yves Brise
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5 a)
Zuerst ausprobieren
ein Bild zu schreiben.
int main()
{
Vector3f pos(-4,0,1);
Vector3f lookat(0,0,1);
Vector3f up(0,0,1);
camera_model camera;
camera = init_camera(pos, lookat, up,1);
color_rgb
color_rgb
color_rgb
color_rgb
color_rgb
color_rgb
rot(1,0,0);
gruen(0,1,0);
blau(0,0,1);
gelb(1,1,0);
schwarz(0,0,0);
weiss(1,1,1);
Grösse des Bildes:
const int res_x = 256;
const int res_y = 256;
color_rgb *pic = ...;
// Allen Bildpunkten blau zuweisen
write_picture(pic);
return 0;
}
Yves Brise
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5 b)
Strahl mit Ebene schneiden.
Ebene soll durch Funktion fixiert sein (xy-Ebene).
float int_plane(ray strahl, Vector3f &normale)
{
// Position der Flaeche (s. Aufgabenstellung
Vector3f plane_n(0,0,1);
float s=0;
// Nomale ist immer die Flaechennormale
normale = plane_n;
// Formel (s. Aufgabenstellung)
if (plane_n.dot(strahl.d) == 0) {
// Schnittpunkt im unendlichen
return -1e30;
} else {
return (s-plane_n.dot(strahl.p))/plane_n.dot(strahl.d);
}
}
Einzige benötigte Operation
ist Vektorprodukt:
Yves Brise
Vector3f a(1,1,1); Vector3f b(1,0,0);
a.dot(b); // gibt float zurück
b.dot(a); // ist äquivalent
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5 c)
float int_sphere(ray strahl, Vector3f &normale)
{
// Position der Kugel
Vector3f c(0,0,0.7);
// Radius
float r=1.2;
// Vektor vom Strahlursprung zum Zentrum der Kugel
Vector3f dst = strahl.p - c;
// Loesen der quadratischen Gleichung
// |t*d + p - c|^2 - r^2 = 0
// = |d|^2*t^2 +2d*(p-c)*t + |p-c|^2 - r^2 = 0
// a1*t*t+b1*t+c1
// a1 = d*d = 1
// b1 = 2*d*dst
// c1 = dst*dst -r*r
float b1 = 2*dst.dot(strahl.d);
float c1 = dst.dot(dst)-r*r;
float d1 = b1*b1-4*c1;
float t = d1 > 0 ? (- b1 - sqrt(d1))/2 : -1.1;
Strahl mit Kugel
schneiden.
Kugel soll durch
Funktion fixiert sein
(c=(0,0,0), r=1.2).
Normale muss
berechnet werden!
// Normale auf der Kugel ist der
// Schnittpunkt - Zentrum
normale = strahl.p + t*strahl.d - c;
normale.normalize();
return t;
}
Yves Brise
20110420 - Übungsstunde 8
Blatt 7, Aufgabe 5 d)
for(int y = 0; y < res_y; y++)
for(int x = 0; x < res_x; x++) {
strahl = generate_ray(x,y,camera);
Endresultat:
farbe = schwarz;
// Hintergrund ist sehr weit weg
t_closest = 1e30;
t = int_sphere(strahl,normale);
if (t>0.0 && t< t_closest) {
// Die Kugel wird getroffen.
// Die Farbe wird rot, die mit der
// Beleuchtung skaliert wird.
farbe = rot;//*(-1*strahl.d.dot(normale));
// AUFGABE C)
farbe = rot*(-1*strahl.d.dot(normale));
// Entfernung wird gespeichert
t_closest = t;
}
t = int_plane(strahl,normale);
if (t>0.00 && t< t_closest) {
// Die Flaeche ist am naechsten. Farbe wird gelb
farbe = gelb;
// AUFGABE C)
farbe = gelb*(-1*strahl.d.dot(normale));
t_closest = t;
}
// Dem Pixel wird die Farbe zugewiesen
pic[y*res_x+x] = farbe;
}
}
Yves Brise
20110420 - Übungsstunde 8
Rekursion
• Funktionen rufen sich selbst oder wechselseitig auf.
• Rekursion ist gleich mächtig wie Iteration.
• Abbruchbedingung wichtig
unsigned int a(unsigned int n, unsigned int m){
if (n == 0) return m + 1;
if (m == 0) return a(n,1);
return a(n, a(n + 1, m));
}
Beispiel:
Ackermann Funktion
a(0, m)
:=
m+1
a(n + 1, 0)
:=
a(n, 1)
a(n + 1, m + 1)
:=
a(n, a(n + 1, m))
Yves Brise
Wächst extrem schnell:
a(3,13) wird auf heutigen
Rechnern schon sehr lange
dauern. a(4,4) grösser als die
Anzahl der Atome im
Uniersum.
20110420 - Übungsstunde 8
Binomialkoeffizient
Implementieren Sie die Funktion binom! Überlegen Sie sich mögliche
Probleme und die Effizienz Ihrer Variante.
A
B
� n�
k
:=
n!
k!(n−k)!

 0,
� n�
1, �
k :=  �
n−1
k
C
+

 0,
� n�
1,�
k := 
�
n n−1
k k−1
�n−1�
k−1
,
if n < k,
if n = k or k = 0,
if n > k, k > 0
if n < k,
if n ≥ k, k = 0,
if n ≥ k, k > 0
unsigned int binom(unsigned int n, unsigned int k);
Yves Brise
20110420 - Übungsstunde 8
Binomialkoeffizient
Variante
A
unsigned int fac(unsigned int n) {
if (n == 0) return 1;
return n * fac(n-1);
}
unsigned int binom(unsigned int n, unsigned int k) {
return fac(n) / fac(k) / fac(n-k);
}
Nachteil: Die Zahlen, die als Zwischenresultate berechnet
werden, sind viel grösser als das Resultat. Frühzeitiger
integer-Überlauf.
Yves Brise
20110420 - Übungsstunde 8
Binomialkoeffizient
Variante
B
unsigned int binom(unsigned int n, unsigned int k) {
if (n < k) return 0;
if (n == k || k == 0) return 1;
return binom(n-1, k) + binom(n-1, k-1);
}
Nachteil: Viele Werte werden mehrfach berechnet. Diese
Rekursion ist sehr ineffizient.
Verbesserung: Speichern Sie die schon berechneten
Werte (Pascalsches Dreieck). Sogenanntes Dynamisches
Programmieren. Dies braucht jedoch mehr Speicher...
Yves Brise
20110420 - Übungsstunde 8
Binomialkoeffizient
Variante
C
unsigned int binom(unsigned int n, unsigned int k) {
if (n < k) return 0;
if (k == 0) return 1;
return n * binom(n-1, k-1) / k;
}
Vorsicht: Wir müssen zuerst multiplizieren und dann erst
durch k dividieren. Ansonsten ist das Resultat sehr
wahrscheinlich falsch wegen der ganzzahligen Division.
Yves Brise
20110420 - Übungsstunde 8
Prüfungsaufgabe
Die Funktion kum3 soll die kumulative Summe der Argumente
berechnen und zurück geben. Das erste Argument bleibt
unverändert, das zweite Argument soll die Summe von a und b
sein. Das dritte Argument c soll zum Ende die Summe aller
Argumente zu Beginn sein.
1. Eignet sich eine gegebene Signatur für
die Implementierung?
2. Falls Ja, dann implementieren Sie die
entsprechende Funktion.
void kum3(int * const a, int * const b, int * const c);
void kum3(int a, int b, int c);
void kum3(const int *a, const int *b, const int *c);
void kum3(int &a, int &b, int &c);
Yves Brise
20110420 - Übungsstunde 8
Prüfungsaufgabe
void kum3(int * const a, int * const b, int * const c);
void kum3(int a, int b, int c);
void kum3(const int *a, const int *b, const int *c);
void kum3(int &a, int &b, int &c);
Implementierung:
void kum3(int * const a, int * const b, int * const c){
*b += *a;
*c += *b;
}
void kum3(int &a, int &b, int &c) {
b += a;
c += b;
}
Yves Brise
20110420 - Übungsstunde 8
Herunterladen