einfache Rekursionen - VLiN · Weitere einfache Rekursionen Bis jetz haben wir direkte Rekursionen...

31
Nach dem umfangreichen Beispiel "Türme von Hanoi" geht es jetz mit Rekursionen aus der Mathematik weiter. Die Berechnung der Fakultät einer natürlichen Zahl n Dieses Problem läßt sich iterativ leicht lösen. Will man n! berechnen, kann man das mit folgender Methode leicht bewerkstelligen: public int nFak(int n) { int ergebnis=1; for(int i= 1;i<n+1;i++) { ergebnis*=i;} // bedeutet : ergebnis = ergebnis*i; return(ergebnis); } Dabei wäre natürlich zu beachten, dass die Fakultät schnell sehr groß wird und den Bereich der Zahlen vom Typ int überschreitet. Das soll aber hier noch keine Rolle spielen. Das Problem läßt sich aber auch rekursiv lösen, wie man an einem einfachen Zahlenbeispiel sieht. Will man 4! berechnen, dann ist das 4 * 3 * 2 * 1 = 4 * ( 3! ) Da aber 3 ! wiederum 3 * ( 2! ) ist und 2! = 2 * ( 1! ) , kann man allgemein formulieren: n! = n * (n-1)! = n* ( (n-1) * (n-2)!) = ...... usw. Die Abbruchbedinigung für die Rekursion ist auch leicht zu sehen. Die Rekursion kommt zum Ende, wenn nur noch n=1 bleibt. Ein modifiziertes UML-Sequenzdiagramm verdeutlicht das noch einmal für das Beispiel 4! 1 1 Blazert, Lehrbuch Grundlagen der Informatik, S.245 Seite 21 einfache Rekursionen © Hans-Georg Beckmann 2004 :nFak nFak(4) nFak(3) nFak(2) nFak(1)=1 ergebnis=1 ergebnis=2*(ergebnis=1) ergebnis=3*(ergebnis=2*(ergebnis=1)) ergebnis=4*(ergebnis=3*(ergebnis=2*(ergebnis=1))) Virtuelle Lehrerfortbildung im Fach Informatik in Niedersachsen

Transcript of einfache Rekursionen - VLiN · Weitere einfache Rekursionen Bis jetz haben wir direkte Rekursionen...

Nach dem umfangreichen Beispiel "Türme von Hanoi" geht es jetz mit Rekursionen aus der

Mathematik weiter.

Die Berechnung der Fakultät einer natürlichen Zahl n

Dieses Problem läßt sich iterativ leicht lösen. Will man n! berechnen, kann man das mit folgender

Methode leicht bewerkstelligen:

public int nFak(int n){int ergebnis=1;for(int i= 1;i<n+1;i++){ ergebnis*=i;} // bedeutet : ergebnis = ergebnis*i;return(ergebnis);}

Dabei wäre natürlich zu beachten, dass die Fakultät schnell sehr groß wird und den Bereich der

Zahlen vom Typ int überschreitet. Das soll aber hier noch keine Rolle spielen.

Das Problem läßt sich aber auch rekursiv lösen, wie man an einem einfachen Zahlenbeispiel

sieht.

Will man 4! berechnen, dann ist das 4 * 3 * 2 * 1 = 4 * ( 3! )

Da aber 3 ! wiederum 3 * ( 2! ) ist und 2! = 2 * ( 1! ) , kann man allgemein formulieren:

n! = n * (n-1)! = n* ( (n-1) * (n-2)!) = ...... usw.

Die Abbruchbedinigung für die Rekursion ist auch leicht zu sehen. Die Rekursion kommt zum

Ende, wenn nur noch n=1 bleibt.

Ein modifiziertes UML-Sequenzdiagramm verdeutlicht das noch einmal für das Beispiel 4! 1

1 Blazert, Lehrbuch Grundlagen der Informatik, S.245

Seite 21

einfache Rekursionen

© Hans-Georg Beckmann 2004

:nFak

nFak(4)nFak(3)

nFak(2)nFak(1)=1

ergebnis=1

ergebnis=2*(ergebnis=1)ergebnis=3*(ergebnis=2*(ergebnis=1))

ergebnis=4*(ergebnis=3*(ergebnis=2*(ergebnis=1)))

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Die Methode "lebt" in vierfacher Ausführung mit jeweils unterschiedlichen Werten der Varia-

blen. Die letzte Aufrufebene hat die kürzeste Lebensdauer und gibt ihr Ergebnis dann an die hö-

here Aufrufebene zurück, deren Leben wiederum mit der Weitergabe des Ergebnisses beendet ist

u.s.w.

Noch einmal die Darstellung mit Programmbefehlen, Stack und Werten am Beispiel 4!

Das Programm verzweigt in der Befehlszeile 2 legt die Werte auf dem Stack ab und ruft sich

selbst wieder auf. Bei der Rückkehr aus Aufrufebene 4 wird das Ergebnis mitgenommen und

führt dann in der Aufrufebene 3 zur Beendigung der Programmzeile 2. Da es eine if ... then ... else

Konstuktion ist, geht es danach in Programmezeile 5 weiter ( Ende ) und die Abarbeitung findet

in der Aufrufebene 2 ihre Fortsetzung.

Wir formulieren diese Lösung in einem kleinen Javaprogramm und lassen sie für verschiedene

Werte von n laufen.

Seite 22

Fakultät

© Hans-Georg Beckmann 2004

Programm- Aufrufebene 1schritt

1 wenn ( n > 1)nFak(4)

2345

sonst ergebnis=4*nFak(3)

Endeergebnis=1

Rückspr.Adresse ergebnis n

Stack-pointer

Mitte 2 4* --- 4

Stack

Programm- Aufrufebene 2schritt

1 wenn ( n > 1)nFak(3)

2345

sonst ergebnis=3*nFak(2)

Endeergebnis=1

Rückspr.Adresse ergebnis n

Stack-pointer

Mitte 2Mitte 2

3* --- 34* --- 4

Programm- Aufrufebene 3schritt

1 wenn ( n > 1)nFak(2)

2345

sonst ergebnis=2*nFak(1)

Endeergebnis=1

Rückspr.Adresse ergebnis n

Stack-pointer

Mitte 2Mitte 2Mitte 2

2* ---3* ---

23

4* --- 4Programm- Aufrufebene 4schritt

1 wenn ( n > 1)nFak(1)

2345

sonst ergebnis=2*nFak(1)

Endeergebnis=1

Rückspr.Adresse ergebnis n

Stack-pointer

Mitte 2Mitte 2Mitte 2

2* 1=23* ---

23

4* --- 4er

gebn

is=

2*1

erge

bnis

=3*

2*1

erge

bnis

=4*

3*2*

1

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

//// Fakul1.java// n-Fakultät rekursiv gelöst// VLIN 32 H.-G.Beckmann, 8/02

import java.awt.*;import java.applet.*;

public class Fakul1 extends Applet { int n; // die Zahl n public void init() { setLayout(null);

}// Ende von init public void paint (Graphics g) { n=6; // z.B. n=6 g.drawString(" Die Fakultät von "+n +" ist " + nFak(n),40,20); } // Ende von paint //*************************************************// Die rekursive Methode//************************************************* public int nFak (int n) { if(n>1) // Abbruchbedingung { return(n*nFak(n-1));} else { return 1;} }// Ende von nFak} // Ende von Applet

Man sieht, dass in der rekursiven Methode zuerst die Abbruchbedingung steht und dann - ohneweitere Variablen zu verwenden - direkt das Ergebnis an die aufrufende Programmebene mit return ... zurückgegeben wird.

Aufgabe:

Mit Variablen vom Typ int ist bei 13! schon kein korrek-

tes Ergebnis mehr zu erhalten. Stellen sie auf den Typ

long um, und testen sie, wie weit man damit richtige Er-

gebnisse bekommen kann. Ihr Tascherechner kann ih-

nen dabei als Kontrolle dienen

Seite 23

Fakultät

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Weitere einfache Rekursionen

Bis jetz haben wir direkte Rekursionen kennengelernt, bei denen eine Methode sich selbst auf-

ruft. Nun sollen an einfachen beispielen indirekte Rekursionen gezeigt werden, bei denen eine

Methode A in einer anderen Methode B und die wiederum in einer Methode C u.s.w aufgerufen

wird, die am Ende möglicherweise wieder von Methode A aufgerufen wird.

In der theoretischen Informatik spielen die primitiv - rekursiven Funktionen bei Berechenbar-

keitsuntersuchungen eine wichtige Rolle.

Man nehme als Basisfunktion die Nachfolgefunktion N(x) = x+1; Sie ordnet jeder ganzen natür-

lichen Zahl einen Nachfolger zu, den wir durch Addition von 1 erhalten.

(Die beiden anderen Basisfunktionen sind die Konstantenfunktion und die Projektion, auf die hier noch nicht eige-

gangen wird.)

Damit kann man nun eine Funktion SUM(x,y) definieren, die rekursiv auf dier Nachfolgefunkti-

on beruht, denn es ist möglich, die Summe x+y dadurch zu erhalten , dass man von x ausgehend

sooft den Nachfolger sucht, wie es y angibt.

Diese Definition muss man per Hand probieren:

SUM(4,3)=N(SUM(4,2)) = N(N(SUM(4,1))) = N(N(N(SUM(4,0)))) = N(N(N(4)))=N(N(5))=N(6)=7

Offensichtlich eine rekursive Funktion !

Als Methode in Java:

public int N(int x)

{ return x+1;}

public int SUM(int x, int y)

{

if(y==0) { return x;} else { return(N(SUM(x,y-1));}

}

Probieren sie diese rekursiven Funktionen in einem kleinen Applet aus.

Seite 24

primitiv - rekursive Funktionen

© Hans-Georg Beckmann 2004

⎧⎨⎩

SUM (x,y) =x falls y=0

N(SUM(x,y-1)) sonst

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Man kann schon ahnen, dass es wohl dann auch möglich sein muss, die Multiplikation zweier

ganzer positiver Zahlen auf die SUM-Funktion zurückzuführen.

Zuerst gilt es wieder eine Abbruchbedingung zu formulieren und dann die Multiplikation auf

eine wiederholte Addition zurüchzuführen:

0 für y=0

SUM(x, MUL(x,y-1)) sonst

Dabei entspricht die erste Zeile der Funktionsdefinition der Abbruchbedingung für die

Rekursion.

Auch das wird zuerst an einem Beispiel genauer vorgerechnet:

MUL(3,3)= SUM(3,MUL(3,2)) = SUM(3,SUM(3,MUL(3,1))) = SUM(3,SUM(3,SUM(3,MUL(3,0)))) =

SUM(3,SUM(3,SUM(3,0))) = SUM(3,SUM(3,3)) = SUM(3,6)=9

Dabei hätte man nun natürlich wieder die Summenfunktion rekursiv durch die Nachfolgerfunk-

tion berechnen lassen können.

Wir können also die Sammlung unserer Javamethoden um MUL erweitern:

public int MUL(int x, int y)

{

if(y==0){return 0;} else { return (SUM(x,MUL(x,y-1)));}

Man kann sich nun schon leicht vorstellen, wie der Stack bei einer Multiplikation durch diese

verschachtelten Rekursionen aussieht.

Probieren sie es an einigen Beispielen aus.

Aufgabe:

Formulieren sie eine Funktionsdefinition für die Potenzierung POT(x,y) = xy, die auf die Funk-

tion MUL zurückgreift.

Seite 25

Nachfolger, Summe, Produkt

© Hans-Georg Beckmann 2004

⎧⎨⎩

MUL (x,y) =

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Aufgabe:

Die oben schon einmal definierte Fakultätsberechnung kann ebenfalls auf die hier angegebene

Art auf MUL zurückgeführt werden. Fügen sie ihrem Applet eine entsprechende Methode hin-

zu.

Testen sie, wie weit das Javaprogramm fehlerfrei läuft. Geht noch die Fakultät von 12 ?

Neben diesen primitiv-rekursiven Funktionen, die auch ein Beispiel für indirekte Rekursion

sind , gibt es weitere Funktionen aus der Mathematik und aus der theoretischen Informatik, die

nicht primitiv - rekursiv sind.

Die Ackermannfunktion

Ein weiteres beliebtes Beispiel für eine rekursive Funktion ist die Ackermannfunktion, die wie

folgt definiert ist:

y +1 falls x=0

Acker(x,y) = Acker(x-1,1) falls y=0

Acker(x-1,Acker(x,y-1)) sonst

Das sieht unfreundlich aus. Es ist eine Funktion mit zwei Parametern und anscheinend unter-

schiedlichen Abbruchbedingungen. Sie sieht auch nicht sehr "zugänglich" aus, da man auf den

ersten Blick nicht erkennt, wie sie sich verhalten wird. Könnten sie z.B. erahnen, was das Ergeb-

nis für Acker (2,3) ist ?

Seite 26

Potenz und Fakultät

© Hans-Georg Beckmann 2004

⎧⎨⎩

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Wir arbeiten das per Hand ab !

Dazu werden wir einige Zwischenergebnisse brauchen, die wir uns bereitstellen:

Acker(1,0)=Acker(0,1)=2

Acker(1,1)=Acker(0,Acker(1,0))=Acker(0,2)=3

Acker(1,2)=Acker(0,Acker(1,1))=Acker(0,3)=4

Acker(2,0)=Acker(1,1)=3

Acker(1,3)=Acker(0,Acker(1,2))=Acker(0,4)=5

Acker(2,1)=Acker(1,Acker(2,0))=Acker(1,3)=Acker(0,Acker(1,2))=Acker(0,4)=5

Nun los :

Acker(2,3)=Acker(1,Acker(2,2)) =Acker(1,Acker(1,Acker(2,1))) =Acker(1,Acker(1,5))=Acker(1,Ak-

ker(0,Acker(1,4)))=Acker(1,Acker(0,Acker(0,Acker(1,3))))=Acker(1,Acker(0,Acker(0,5)))=Ak-

ker(1,Acker(0,6))=Acker(1,7)=Acker(0,Acker(1,6))=Acker(0,Acker(0,Acker(1,5)))=Acker(0,Ak-

ker(0,7))=Acker(0,Acker(0,7))Acker(0,8)=9

Wer weiß, ob das wirklich stimmt. Hier muss offensichtlich ein Programm her, dass uns diese

Rechenarbeit abnimmt. ( Es soll übrigens Lehrer geben, die als einzige Aufgabe für eine mehr-

stündige Klausur Acker (8,12) zu Fuß berechnen lassen)

Das Applet für die Berechnung der Ackermannfunktion ist im Prinzip genauso aufgebaut, wie

das für die Fakultät. In seiner einfachsten Form hat man:

//// Ackermann1.java// Die Ackermannfunktion , eine "klassische Rekursion"// Hans-Georg Beckmann 8/2004// vlin 32//////////////////////////////////////////////////////////////////////////////////

import java.awt.*;import java.applet.*;

public class Ackermann1 extends Applet {

long x,y; // die beiden Parameter der Funktion Font font = new Font("serif", Font.ITALIC + Font.BOLD, 16); // ein Font

//*************************************************************

Seite 27

Ackermannfunktion

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

public void init() { setLayout (null); x=3; y=2; }// Ende von Init

//*************************************************************

public void paint (Graphics g) { g.setFont(font); g.drawString(" Die Ackermannfunktion hat für x = "+x +" und y= "+y+"

den Wert "+Acker(x,y),20,50); }// Ende von paint

//*************************************************************

public long Acker(long x, long y) { if(x==0) {return(y+1);} else {if(y==0) {return(Acker(x-1,1));} else {return(Acker(x-1,Acker(x,y-1)));} } }// Ende von Acker}// Ende von Applet

Aufgabe:

Die Ackermannfunktion soll für Wertepaare von (0,0) bis (4,4) berechnet werden. Die Ergebnisse

sollen übersichtlich ausgegeben werden, wie im nachfolgenden Screenshot zu sehen.

Realisieren sie das Beispiel mit Labels oder Buttons oder nur mit grafischer Ausgabe.

Wie man im Ergebnis sieht, sind einige Felder nicht ausgefüllt. z.B. fehlen Acker(4,1) bis

Acker (4,5). Das Runtimesystem ( die virtuelle Javamaschine VM) meldete in diesem Falle "stack

overflow", eine Fehlermeldung, von der man meinte, dass sie der Vergangenheit angehört.

Seite 28

Ackermannfunktion

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Betrachtet man die Funktion, dann kann man erahnen, welche Rekursionstiefe die Berechnung

erreicht. Der Stack reicht dann in seiner vom System vorgegebenen Größe nicht mehr aus. In ei-

nigen Internetbrowsern erscheint überhaupt nichts im Browserfenster, andere "hängen sich auf "

und einige (z.B. Opera ) zeigen das obige Bild.

Haben sie also bitte gehörigen Respekt vor dieser Funktion, die immerhin in der Lage ist, ausge-

wachsene Gigahertzmaschinen zum Stillstand zu bringen, ohne dass man etwas Falsches pro-

grammiert hat.

Aufgaben

1) Eine weitere rekursive Funktion, die gerne vorgeführt wird, ist die ULAM-Funktion. 2

Sie ist wie folgt definiert:

1 für x= 1

ULAM (x) = ULAM(x/2) für x>1 und x gerade

ULAM(3*x + 1) für x>1 und x ungerade

2 Stanislav Marcin Ulam, 3.4.1909 - 13.5.1984 polnischer Mathematiker . Bekannt durch die "Monte Carlo Metho-de" in der Statistik, durch Mitarbeit bei der Entwicklung der H-Bombe in den USA und durch allerlei Zahlenspie-lereien ( u.a. die Ulamsche Zahlenspirale )

Seite 29

Ackermann und Stack Overflow

© Hans-Georg Beckmann 2004

⎧⎨⎩

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Schreiben sie ein Javaprogramm / Javaapplet das rekursiv läuft und die Zwischenergebnisse

ausgibt. Lassen sie es es mit verschiedenen Startwerten laufen. Sie sollten sich hoffentlich an das

Achterbahnzahlprogramm erinnert fühlen.

2) Eine weitere Funktion , die nach einem bekannten Mathematiker benannt wurde ist die

Hofstadterfunktion 3:

1 für n= 1 oder n = 2

HOF(n - HOF(n-1)) + HOF (n - HOF(n-2)) für n >2 ist.

Schreiben sie ein Javaprogramm / ein Javaapplet für die Hofstadterfunktion. Berechnen sie HOF(4) mit

Bleistift und Papier.

Rekursionen und Grafik

Nach soviel Mathematik soll uns ein wenig rekursive Grafik erfreuen. Viele Grafiken, die auf Wiederho-

lungen gleicher Figuren mit unterschiedlichen Größen beruhen kann man sowohl als Iteration programmie-

ren als auch in Form einer Rekursion. Auch wenn weiter oben darauf hingewiesen wurde, dass Rekursio-

nen als elegant gelten, muss man doch bedenken, dass bei einer Iteration nicht mit stack overflow zu rech-

nen ist. Daher gilt auch für die nachfolgenden ersten Beispiele, dass es vollkommen in Ordnung ist, wenn

man die Grafiken nicht rekursiv erstellt. Danach aber werde die Problemstellungen nur noch rekursiv lös-

bar sein.

3 Douglas R. Hofstadter 1945 - , Mathematiker, Autor von "Gödel, Escher , Bach "und Robert Hofstadter, Physiker, Nobelpreisträger

Seite 30

Aufgaben

© Hans-Georg Beckmann 2004

⎧⎨⎩

HOF( n ) =

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Wir beginnen mit einem einfachen Muster aus ineinander geschachtelten Rechtecken.

Offensichtlich ist die Iteration recht simpel:

public int zufall (int zz) // ein Zufallsgenerator für ganze Zahlen { return (int) (Math.random()*zz); }

public void paint (Graphics g) // Hier die Iteration in der paint Methode { g.setColor(Color.blue); g.setFont(font); g.drawString(message, 150, 30); for(int i=0;i<40;i++) { x=20+i*6; y=40+i*6; breit=400-i*12; hoch=400-i*12; g.setColor( new Color(zufall(255),zufall(255),zufall(255))); g.drawRect(x,y,breit,hoch); } }

Das ist der Ausschnitt aus der paint-Methode, der so und in modifizierter Form ( mit Zufallsfarben ) die

nachfolgenden Bilder liefert.

Aber auch eine Rekursion ist für dieses einfache Muster kein Problem. Wir schreiben eine eigene rekursive

Methode, der ein Grafikkontext g übergeben wird und die einen Zähler verwaltet, der als Abbruchbedin-

gung benutzt wird. Dabei ist es unerheblich, ob der Zähler aufwärts oder abwärts zählt, wichtig ist nur ,

dass die Abbruchbedingung erfüllt werden kann.

Seite 31

einfache rekursive Grafiken

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

Schauen sie sich die Rekursion an, schreiben sie ein entsprechendes Applet und experimentieren sie ein

wenig damit herum.

//******************************************************// die rekursive Methode//******************************************************public void mustermalen(int z, Graphics g) { if(z<30) // die Abbruchbedingung: solange der Zähler z kleiner als 30 ist... { g.setColor( new Color(zufall(255),zufall(255),zufall(255))); // Farbe;

// zufall siehe o. g.fillRect(20+z*6,40+z*6,400-z*12,400-z*12); mustermalen(z+1,g); // Aufrufen mit Zähler +1 } } public void paint (Graphics g) { g.setColor(Color.blue); g.setFont(font); g.drawString(message, 150, 30); mustermalen(1,g); }

Ganz offensichtlich ist es nicht sehr schwer,

solche Iterationen als Rekursionen zu schrei-

ben. Das macht nun aber keinen besonderen

Reiz aus, und deshalb sollen andere Grafiken

behandelt werden, für die Rekursionen das ge-

eignete Mittel sind.

Fraktale Objekte - Sierpinskidreieck

Ein erstes Beispiel ist das Sierpinskidreieck 4.

Man stelle sich vor, ein schwarz gefülltes Dreieck auf ein

Blatt Papier zu malen. Dann markiert man auf den Seiten je-

weils die Mitte, verbindet dies drei Mittelpunkte und schnei-

det das entstehende Dreieck aus. Man hat ein schönes drei-

eckiges Loch im Papier. Was bleibt sind drei schwarze Teild-4 Waclaw Sierpinski. 14.3.1882 - 21.10.1969, polnischer Mathematiker

Seite 32

rekursives Mustermalen

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

reiecke. Mit denen macht man dasselbe nun wieder. Man bekommt drei neue Löcher im Papier,

die natürlich etwas kleiner sind. Es bleiben jetzt 9 kleinere schwarze Dreiecke übrig, mit denen

man ........

Das ruft nach Rekursion.

Das Rekursionsschema muss etwa folgendermaßen aussehen:

Die Dreiecke werden als Polygone verwaltet und mit fillPolygon schwarz oder weiß gefüllt.

Es ensteht am Ende eine bekannte Figur. Sie erinnern sich an die Karawanenaufgabe ?

Hier taucht das Sierpinskidreieck wieder auf, obwohl es hier vollständig anders konstruiert ist.

Dieses Dreieck ist sehr eigenartig. Nehmen sie an, die Seitenlänge des Ausgangsdreiecks sei a,

dann ist der Umfang der schwarzen Fläche in der ersten Stufe U0=3*a.

In der zweiten Stufe ist der Umfang aller drei schwarzen Flächen zusammen U1 =9/2 *a .

In der dritten Stufe ist es U2 =27/4*a und allgemein ist es eine geometrische Folge mit

Un = a*3(n) die offensichtlich divergiert, also gegen Unendlich läuft.

Betrachtet man den Flächeninhalt, also das Papier, das jeweils nach dem Schnippeln übrig ist,

Seite 33

Fraktales; Sierpinski

© Hans-Georg Beckmann 2004

Berechne die Koordinaten der Mittelpunkte der SeitenLösche das innere Dreieck,mit den gerade berechneten EckpunktenBerechne die SeitenlängeSolange die Seitenlänge nicht zu klein ist

Berechne die Koordinaten der Mittelpunkte des oberen TeildreiecksLösche das innere Dreieck,mit den gerade berechneten EckpunktenBerechne die Koordinaten der Mittelpunkte des Teildreiecks links untenLösche das innere Dreieck,mit den gerade berechneten EckpunktenBerechne die Koordinaten der Mittelpunkte des Teildreiecks rechts untenLösche das innere Dreieck,mit den gerade berechneten Eckpunkten

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

dann nimmt die Fläche immer ab. Sei die Fläche am Anfang A dann ist

A0 = A und A1 = 3/4*A und A2=9/16 *A und A3=27/64*A und allgemein An= (3/4)n * A

Auch das ist eine geometrische Folge. Diese konvergiert aber gegen Null.

Man hat also als Grenzfigur eine Fläche ohne Inhalt, mit einem unendlichen Umfang.

Die geometrische Dimension liegt damit zwischen Dimension 1 ( für eine Gerade oder Strecke )

und Dimension 2 ( für eine Fläche ). Daher auch die Bezeichnung "Fraktale".

Es gibt ein exaktes Verfahren zur Bestimmung der gebrochenen Dimension solcher geoemtri-

scher Objekte, die hier aber nicht interssieren soll.

Lassen sie ihre Schülerinnen und Schüler weite-

re Beispiele finden ( Menger - Schwamm, Kan-

tor-Staub etc.)

Aufgabe:

Schreiben sie ein Applet, das rekursiv dieses

Sierpinskidreieck erzeugt. Zum Zeichnen und

erzeugen eines Polygons schlagen sie in Krüger,

GotoJava , Kapitel 23 nach.

Wir werden noch weitere seltsame Objekte die-

ser Art kennenlernen. Dazu brauchen wir einige

spezielle Grafikroutinen, die Java nicht automa-

tisch zur Verfügung stellt.

Die Turtlegrafik

In der Programmiersprache LOGO aber aus in einigen Versionen von Pascal und C++ taucht im-

mer wieder die sogenannte Turtlegrafik auf, die ursprünglich von Seymour Papert am MIT für

die Sprache LOGO entwickelt wurde. Dabei stellt man sich eine Schildkröte ( in der einge-

deutschten Fassung einen Igel ) vor, die mit einem Filzstift im Maul über eine Malfläche kriecht.

Dabei kann sie den Kopf senken, so dass der Stift eine Spur hinterläßt oder aber sie kann mit er-

hobenem Maul schreiten ohne einen Strich auf dem Untergrund zu hinterlassen. (Ja so sind sie ,

die Schildkröten ). Als folgsames Tier gehorcht die Turtle allen Befehlen, die ihr der Programmie-

Seite 34

Sierpinskidreieck

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

rer angibt. Sie kann VorWärts und RückWärts gehen, den StiftAbsen-

ken oder den StiftHeben, nach REchts drehen und nach LInks drehen

und zur MItte des Blattes laufen. Man kann ihr bei Bedarf noch viele

weitere Eigenschaften geben ( Farbwechsel, Aufkurs setzen,........)

In der Auflistung ihrer Fähigkeiten wird schon deutlich, wie die ein-

zelnen Methoden unserer Turtle heißen könnten.

Es liegt auf der Hand, dass die Turtle eine eigenen Klasse darstellt, die

wie nebenstehend aussehen soll.

Dass dabei viele der internen Vraiablen vom Typ double sind, obwohl

am Ende nur ganzzahlige Bildschirmkoordinaten möglich sind, liegt

daran, dass nicht zu früh innerhalb der Rechnungen auf ganze Zahlen

gerundet werden darf, weil sonst die Ungenauigkeiten zu groß wer-

den.

Im Konstruktor werden von außen die Appletmaße übergeben. Daraus wird dann die Startposi-

tion der Turtle ermittelt. Die Anfangsrichtung , in die die Turtle schaut hat den Winkel 0 Grad,

was auf dem Bildschirm der Blickrichtung nach Osten entspricht.

Unsere Schildkröte bekommt eine eigene Malfläche und daher erweitert sie die Klasse Canvas

//*****************************************************************//// Die Klasse Turtle ////***************************************************************** public class Turtle extends Canvas { private int xmitte,ymitte; private double richtung,xpos,ypos; private boolean status; //Hier wird bestimmt, ob Stift unten oder oben Graphics g; //*****************************************************************// Der Konstruktor nimmt von außen die Breite und Höhe // des Appletwindows an//***************************************************************** public Turtle(int breit, int hoch) // der Konstruktor { g=getGraphics(); // hole den Grafikkontext von außen xmitte=breit/2-20; // Turtlestartwert x ymitte=hoch/2-20; // Turtlestartwert y richtung=0; xpos=(double)xmitte; // das ist dann auch die aktuelle ypos=(double)ymitte; // Position

Seite 35

Turtlegrafik

© Hans-Georg Beckmann 2004

class Turtle- xmitte:int- ymitte:int- richtung:double- xpos:double- ypos:double- status:boolean- g:Graphics

<< constructor>>+ Turtle(int,int)

<<methoden>>+ VW(int)+ RW(int)+ LI(int)+ RE(int)+ SA()+ SH()+ MITTE()

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

status=true; // Stift ist unten }//*********************************************************// Vorwärts laufen//********************************************************* public void VW(int strecke) { double xneu,yneu; double bogen=richtung*Math.PI/180; // Winkel werden im Bogenmaß gebraucht Graphics g = getGraphics(); xneu=xpos+(Math.cos(bogen)*strecke); yneu=ypos+(Math.sin(bogen)*strecke); if(status==true) {g.drawLine((int)xpos,(int)ypos,(int)xneu,(int)yneu);}

// Nur Zeichnen wenn Stift unten xpos=xneu; // die neuen Koordinaten werden zur ypos=yneu; // aktuellen Position }// Ende von VW//********************************************************// Rückwärts beruht auf drehen und Vorwärts//******************************************************** public void RW(int strecke) { double xneu,yneu; richtung=(richtung+180)%360; // um 180 Grad modulo 360 Grad drehen double bogen= richtung*Math.PI/180; Graphics g = getGraphics(); xneu=xpos+(Math.cos(bogen)*strecke); yneu=ypos+(Math.sin(bogen)*strecke); if(status==true) {g.drawLine((int)xpos,(int)ypos,(int)xneu,(int)yneu);} xpos=xneu; ypos=yneu; richtung= richtung=(richtung+180)%360; // Wieder auf alten Wert zurück }// Ende von RW//********************************************************// Rechts drehen und Links drehen//******************************************************** public void RE(int winkel) { richtung=(richtung+winkel)%360; } public void LI(int winkel) { richtung=(richtung-winkel)%360; }//*********************************************************// Stift hoch und runter //*********************************************************

public void SA(){ status=true;}public void SH(){ status=false;}

Seite 36

Turtlegrafik

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

//***********************************************************// zurück auf Ausgangsposition//***********************************************************

public void MITTE(){ xmitte=breit/2-20; // Turtlestartwert x ymitte=hoch/2-20; // Turtlestartwert y richtung=0; xpos=(double)xmitte; // das ist dann auch die aktuelle ypos=(double)ymitte; // Position status=true; / Stift ist unten }

}// Ende von Klasse Turtle

Zur Verfügung stehen uns die Grafikbefehle von Java, die wir an vielen Beispielen kennengelernthaben. Das ist in erster Linie der Befehl drawLine(int,int,int,int), den wir hier verwenden.Wir müssen für die Bewegung der Turtle immer ihre aktuelle Position am Bildschirm verwalten ( das geschieht mit den Attributen xpos und ypos ). Dann müssen wir gegebenenfalls aus der Be-wegung ihre neuen Koordinaten bestimmen und sie nach der Bewegung wieder in xpos und yposspeichern. Genauso muss man ihre Blickrichtung verwalten, was in der Variablen richtung ge-schieht.Da die Turtle alle Eigenschaften von Canvas erbt, braucht sie zum Zeichnen nicht die paint-Mte-hode des Applets. Sie kann das schon von selbst.

Nun muss dafür gesorgt werden, dass eine Turtle zum Leben erweckt wird. Außerdem soll sieZeichenfläche sich vom Appletfenster ein wenig abheben und die Turtle soll loslaufen, wennman einen Button klickt. Damit sieht der Anfang des Programms wie folgt aus:

// Turtle1.java// eine Implementation der Turtlegrafik// siehe auch Cornelsen "Praktische Informatik mit Java" und // Login Heft 6 1997 und andere Quellen// angepasst und erweitert Hans - Georg Beckmann 8/2004// VLIN 37

import java.awt.*;import java.applet.*;import java.awt.event.*;

public class Turtle3 extends Applet implements ActionListener{ Button myButton= new Button("Start"); // der Button Turtle myTurtle; // eine neue Turtle int breit,hoch; // Die Maße des Applets

public void init() {

setLayout (null); breit=getBounds().width; // Breite des Appletfensters

Seite 37

Turtlegrafik

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

hoch=getBounds().height; // Höhe des Appletfensters // Damit ein netter Rand um die Turtlemalfläche zu sehen ist // bekommt die Turtle nicht die ganze Breite und Höhe zugeteilt

myTurtle=new Turtle(breit-40,hoch-40); myTurtle.setBounds(20,20,breit-80,hoch-80); // Plazieren im Fenster myButton.setBounds(breit/2-40,hoch-25,80,20); // Buttonkoordianten myTurtle.setBackground(new Color(220,235,235)); // was nettes helles // Die Turtle erweitert Canvas und muss daher als Objekt mit add im // Applet untergebracht werden add(myTurtle); add(myButton); myButton.addActionListener(this); // this, weil das Applet den // ActionListener implementiert }// Ende von init

Damit sind alle Objekte initialisiert und im Appletfenster untergebracht.

Jetzt könnte man sie Methode actionPerformed ganz leicht nutzen ,

um die ersten Malversuche mit der Schildkröte vorzunehmen.

public void actionPerformed(ActionEvent myEvent)

{

myTurtle.VW(60);

myTurtle.RE(90);

myTurtle.VW(60);

myTurtle.RE(90);

myTurtle.VW(60);

myTurtle.RE(90);

myTurtle.VW(60);

myTurtle.RE(90);

}// Ende von actionPerformed

Nicht so sehr überzeugend. Ein Quadrat hätten wir wohl auch anders hinbekommen. Machen

wir es etwas komplizierter. Wie erzeugen eine Klasse Vieleck, die ein N-Eck zeichnet. Dabei rich-

tet sich die Seitenlänge nach der Eckenzahl und der Größe des Appletfensters.

//********************************************************//// Beispielsweise eine Klasse Vieleck ohne Konstruktor////********************************************************class Vieleck{ public Vieleck() {} // leerer Konstruktor public void zeichnen (int Eckenzahl)

Seite 38

Turtlegrafik

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

{ int strecke; strecke=1+(int) myTurtle.getBounds().width/Eckenzahl; for ( int i=0;i<Eckenzahl;i++) {

myTurtle.VW(strecke); myTurtle.RE((int) 360/Eckenzahl); }// Ende von for }// Ende von zeichnen}// Ende von Vieleck

Damit man etwa ein Achteck am Bildschirm zu sehen bekommt,

muss man eine Instanz der Klasse Vieleck erzeugen ( ganz am An-

fang des Programms )

Vieleck neck=new Vieleck();

und dann in actionPerformed nur noch als Anweisung

public void actionPerformed(ActionEvent myEvent)

{

neck.zeichnen(8);

}// Ende von ActionPerformed

angeben.

Aufgaben

1) Erzeugen sie nebenstehende Figur durch geschach-telte Wiederholungsanweisungen. Die Figur bestehtaus Quadraten.

2) Prüfen sie, ob man mit der Klasse Vieleck auch Krei-se zeichen kann.

Es wäre nicht notwendig, das Vieleck als eigenen Klasse zu definieren. Es reicht auch eine Zei-chenmethode im Applet.Bevor wir uns an rekursive Methoden machen, noch zwei kleine Zusatzmethoden: Auch wenn wir auf paint() verzichten können, werden wir diese Methode und die Methode up-date verwenden, um bei Veränderung der Fenstergröße ( z.B. im Browser ) die Turtle den verän-derten Größen anzupassen, die Zeichenfläche neu zu dimensionieren und den Button neu zu set-zen.

Seite 39

Turtlegrafik, erste Zeichnungen

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

public void update(Graphics g) { breit=getBounds().width; //aktuelle Breite holen hoch=getBounds().height; //aktuelle Höhe myTurtle.setBounds(20,20,breit-80,hoch-80); myTurtle.setBackground(new Color(220,235,235)); // was nettes helles myButton.setBounds(breit/2-40,hoch-25,80,20);

myTurtle.MITTE(); // auf Startposition }public void paint(Graphics g) { update(g); }

Nun haben wir Alles, was die Turtle braucht. Bevor es in Rekursionen geht, ein Hinweis:Diese Klasse für die Turtlegrafik ist vielfältig verwendbar. Man kann die Simulation von Robo-tern behandeln , die ihre Bewegungsbefehle aus einer sequentiellen Textdatei holen. Man kann Labyrinthe erzeugen oder sich in ihnen bewegen( geben sie dazu der Turtle noch ei-nen Sensor, der Hindernisse erkennt ). Mit Maus oder Tastatur kann man eine Turtlesteuerung erzeugen, die sogar für einfache Spieleausreicht.Viele Beispiele für den Informatikunterricht der Sekundarstufe 1 basieren auf ähnlichen Konzep-ten ( z.B. Nicki der Roboter ). Am Ende kann man sogar Programme für die Turtle schreiben las-sen, die dann ein Interpreter abarbeitet und am Bildschirm ausführt.

Turtlerekursionen 1

Erzeugen sie die Klasse rekurs1

//****************************************************************// die erste rekursive Figur//****************************************************************class rekurs1 // Ohne Konstruktor entspricht leerem Konstruktor{ public void zeichnen(double strecke) { if(strecke<5) // Abbruchbedingung { myTurtle.VW(4); } else { myTurtle.RE(45); // Drehen zeichnen(strecke/Math.sqrt(2)); // Rekursion myTurtle.RE(-90); // Zurückdrehen zeichnen(strecke/Math.sqrt(2)); // Rekursion myTurtle.RE(45); // Drehen }// Ende von Else }// Ende von Zeichen}//Ende von rekurs 1

Seite 40

Turtlegrafik

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

Auch hier müssen sie ein Expemplar der Klasse rekurs1 erzeugen ( am Anfang des Applets )

rekus1 myrekurs=new rekurs1();

In actionPerformed kann man dann einsetzen

public void actionPerformed(ActionEvent myEvent)

{

myrekurs.zeichnen(100);

}// Ende von actionPerformed

Am Bildschirm erscheint ein verzwicktes Muster. Expe-

rimentieren sie mit der Variablen Strecke und auch mit

der Streckenverkürzung in der rekursiven Methode, in-

dem sie z.B.

zeichnen(strecke/Math.sqrt(1.5));

verwenden.

Turtlerekursionen 2 - ein Baum

Ein Baum soll auf folgende Art wachsen:

Seite 41

Turtlegrafik und Rekursionen

© Hans-Georg Beckmann 2004

Drehe auf Winkel 90 Grad

Baum ( Strecke s)Wenn Strecke noch lang genug

Gehe eine Strecke s nach vornDrehe um Winkel alpha nach linksGehe Strecke s nach vornDrehe Winkel alpha nach rechts

Drehe Winkel alpha nach linksGehe Strecke s zurückDrehe um 2*Alpha nach rechtsGehe Strecke s nach vornDrehe alpha nach links

Drehe rechts um Winkel Aplha

Baum (Strecke s/2)

Baum (Strecke s/2)

Gehe Strecke s zurückDrehe um Winkel alpha nach links

Ende Gehe Strecke s zurück

Baum (s)

Baum (s/2)

Baum ((s/2)/2)

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Dabei ist der Winkel Alpha noch frei wählbar. Er könnte z.B. 90 Grad betragen, was zur Folgehätte, dass sich die Baumteile in der Grafik nicht überlagern. Man kann auch die Streckenverkür-zung ändern und auf diese Weise verschiedene binäre Bäume wachsen lassen.Eine entsprechende Klasse sieht dann wie folgt aus:

//**************************************************************************// Ein binärer Baum//**************************************************************************class BinBaum{ int alpha; public BinBaum(int winkel) // Konstruktor { alpha=winkel; // Hole dir den Winkel von außen } public void zeichnen (int strecke) { if(strecke>2) // Abbruchbedingung { myTurtle.VW(strecke); myTurtle.LI(alpha); myTurtle.VW(strecke); myTurtle.RE(alpha); // Schaut wieder nach oben zeichnen((int)strecke/2); // Rekursiver Aufruf // myTurtle.SH(); könnte man machen myTurtle.LI(alpha); // Zur Mitte zurück und auf die rechte Seite myTurtle.RW(strecke); myTurtle.RE(2*alpha); // myTurtle.SA(); könnte man machen myTurtle.VW(strecke); myTurtle.LI(alpha); // schaut wieder nach oben zeichnen((int)strecke/2); // Rekursiver Aufruf myTurtle.RE(alpha); // Nun wieder zur Wurzel zurück myTurtle.RW(strecke); myTurtle.LI(alpha); myTurtle.RW(strecke); }// Ende von if }// Ende von zeichnen}// Ende von BinBaum

ein Exemplar des Baums wird z.B mit

BinBaum myBinBaum= new BinBaum(60); // Winkel alpha 60 Grad

erzeugt.

Seite 42

Turtlegrafik und Rekursionen

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

In der Methode actionPerfomed wird es dann folgendermaßen aussehen.

public void actionPerformed(ActionEvent myEvent) { int strecke; strecke =getBounds().height/4-10; // kann man ändern myTurtle.LI(90); // Nach oben schauen myTurtle.SH(); // nicht malen myTurtle.RW(strecke); // fast bis an den unteren Rand gehen myTurtle.SA(); myBinBaum.zeichnen(strecke); // los geht´s }// Ende von actionPerformed

Man kann das Beispiel erweitern und einen ternären Baum erschaffen, der nicht zwei Äste hat,

sondern jeweils drei. Man muss die Klasse BinBaum dazu nur wenig erweitern und erhält dann

ein Bild, dass uns schon auf verschiedene andere Art untergekommen ist.

Die Klasse ist recht übersichtlich:

Seite 43

Turtlegrafik ,Rekursionen und Bäume

© Hans-Georg Beckmann 2004

alpha = 60°

alpha = 90°

alpha = 120°

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

//**************************************************************************// Ein ternärer Baum mit festem Winkel 120 Grad//**************************************************************************class TriBaum{ public TriBaum() //leerer Konstruktor {} public void zeichnen (int strecke) { if(strecke>1) //Abbruchbedingung { myTurtle.VW(strecke); zeichnen(strecke/2); // Rekursion myTurtle.RW(strecke); myTurtle.LI(120); myTurtle.VW(strecke); zeichnen(strecke/2); // Rekursion myTurtle.RW(strecke); myTurtle.LI(120); myTurtle.VW(strecke); zeichnen(strecke/2); // Rekursion myTurtle.RW(strecke); myTurtle.LI(120); }// Ende von if }// Ende von zeichnen}// Ende von TriBaum

Schon wieder Sierpinski !

Seite 44

Turtlegrafik ,Rekursionen und Bäume

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

Aufgabe

Ein weiteres bekanntes Beispiel eines fraktalen Gebildes ist die Schneeflockenkurve oder auch

Kochkurve 5.

In einer Strecke der Länge s wird das mittlere Drittel durch eine Zacke ersetzt. Die vier Teilstrek-

ken sind gleichlang. Jede der Teilstrecken wird im nächsten Schritt wieder im mittleren Drittel

eine Zacke bekommen. Und so geht es immer weiter.

Macht man das für die drei Seiten eines

gleichseitigen Dreiecks, bekommt man eine

geschlossene Kurve, die einer Schneeflocke

ähnelt.

Dabei führt man die Rekursion nach einan-

der für die drei Seiten des Dreiecks aus und

versucht nicht etwa die Rekursion auf das

ganze Objekt anzuwenden.

Verändern sie das Turtlegrafikprogramm

entsprechend und erzeugen sie Kochkurven

verschiedener Rekursiontiefe.

5 Helge von Koch, 1870 - 1924Schwedischer Mathematiker

Seite 45

Turtlegrafik ,Rekursionen und Fraktale

© Hans-Georg Beckmann 2004

Stufe 0

Stufe 1

Stufe 2

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

L-Systeme

Kurven wie die zuletzt geschilderten lassen sich durch sogenannte L-Systeme beschreiben.

Der Biologe Aristid Lindenmeyer 6 hat 1968 ein System zur Beschreibung von Pflanzenwachs-

tum gesucht, das wie eine Sprache mit fester Grammatik und wenigen Zeichen funktioniert. Die

erzeugten Zeichenfolgen sind Worte, die sich als Zeichnungen darstellen lassen. Diese Systeme

werden uns bei der Untersuchung endlicher Automaten noch einmal genauer beschäftigen.

Angepasst auf unsere Turtlegrafik gibt es folgende Symbole:

F Die Turtle zeichnet eine Strecke ( Forward)M Die Turtle geht eine Strecke mit SH (Move)s der Streckungsfaktor für die Figur* Die Länge einer Linie wird mit s multilpiziert: Die Länge wird durch s dividiertαααα ist der Drehwinkel für die Turtle+ Winkelvorzeichen= Drehung gegen den Uhrzeigersinn ( LI )- Drehung im Uhrzeigersinn (RE )| Drehung um 180 Grad[ Stackoperation;aktuelle Position Richtung auf Stack legen] Stackpoeration;aktuelle Position und Richtung vom Stack holen

Die Kochkurve beginnt mit einer Strecke also dem Zeichen F. F heißt der Initiator der Kochkurve.In der nächsten Stufe gilt nun für unsere Turtle folgende Abfolge von Anweisungen:

F + F - - F + F

Diese Zeichenfolge heißt Generator der Kockkurve.Und man muss natürlich noch den Winkel α angeben , der hier 60° beträgt.Die Regeln zur Erzeugung der Kochklurve sind also:

1. F der Initiator

2. F --> F + F - - F + F der Generator; ersetze F durch die Zeichenfolge F+F--F+F

3. α = 60° der Winkel

6 Aristid Lindenmeyer 1925 - 1989, dänischer Biologe

Seite 46

L-Systeme

© Hans-Georg Beckmann 2004

Vorwärts Drehe um αααα = 60 ° Vorwärts Drehe 2 mal um αααα = - 60 ° Vorwärts Drehe um αααα = 60 ° Vorwärts

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Damit läßt sich auch die Gesamtkurve, die auf einem gleichseitigen Dreieck basiert, als Regel-werk angeben.

1. F - - F - - F der Initiator; ein gleichseitiges Dreieck

2. F --> F + F - - F + F der Generator; wie oben

3. α = 60° wie oben

Ein weiteres Beispiel ist die Schneeflockenkurve nach Cesaro 7, die folgenden Regeln gehorcht:

1. F - F - F - F - F - F der Initiator ist offensichtlich ein Sechseck

2. F ---> F - F + + F - F der Generator

3. α = 60°

Wenn wir diese Regeln in unserm Javaprogramm unterbringen wollen, lässt sich die Rekursionfolgendermaßen formulieren ( beide Methoden sind in einer Klasse Schneeflocke enthalten , vonder wir eine Instanz mySchneeflocke erzeugt haben).

public void generator (int strecke, int tiefe){if(tiefe > 1){

generator(strecke/3,tiefe-1);myTurtle.RE(60);generator(strecke/3,tiefe-1);myTurtle.LI(60);myTurtle.LI(60);generator(strecke/3,tiefe-1);myTurtle.RE(60);generator(strecke/3,tiefe-1);

}else myTurtle.VW(strecke); // irgendwann muss ja auch mal gemalt werden

}// Ende von Zeichnen

public void initiator(int strecke, int tiefe){

for(int i=0;i<6;i++){generator(strecke,tiefe);myTurtle.RE(60);}

}

7 Ernesto Cesaro 1859 - 1906 , italienischer Mathematiker

Seite 47

L-Systeme

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen

Wird dann in actionPerformed mySchneeflocke.initiator(400,8) aufgerufen, dann ensteht eine Kurve,

in der die Generatoranweisung 8 mal rekursiv aufgerufen wird. Dabei wird die Strecke jeweils

passend verkleinert.

Es ist eine nach innen gekehrte Kochkurve.

Dabei gilt diesmal als Abbruchbedingung nicht

die Länge einer Strecke sondern die Tiefe , bis

zu der gearbeitet wird. Man beginnt mit dem

Aufruf zeichnen(8) und die Rekursion arbeitet

dann solange, bis die Tiefe 1 erreicht ist.

Hiermit hat man ein elegantes Mittel zur Hand,

dass es erlaubt, auch recht komplizierte rekur-

sive Grafiken leicht zu beschreiben.

Ein letztes Beispiel soll hier die Hilbert-Kurve

sein. 8

Wenn man keine L-Systeme verwendet, ist die

Hilbertkurve ein sehr schönes Beispiel für indi-

rekte Rekursionen, da vier Methoden A,B,C

und D sich gegenseitig aufrufen. Nicolas Wirth

hat das in "Algorithmen und Datenstrukturen,

Abschnitt 3.3 " sehr übersichtlich dargestellt.

Betrachtet man die ersten beiden Schritte der

Kurve, dann erkennt man nicht ohne Weiteres

die Rekursion.

Welcher Zusammenhang besteht also zwi-

schen den Kurven H(1), H(2) und H(3) ?

Formulieren wir eine "Zeichnungsvorschrift"

für die Erstellung einer Kurve.

8 David Hilbert ,geb.23.1.1862 in Königsberg, gest. 14.2.1943 in Göttingen. Einer der berühmtesten Mathematikerdes letzten Jahrhunderts. Prof. der Mathematik in Göttingen ab 1895

Seite 48

Koch, Cesaro und Hilbert

© Hans-Georg Beckmann 2004

H(1)

H(2)

H(3)

Hilbertkurven der Ordnung 0, 1 und 2

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Nennt man das offenen Rechteck, das in H(1) zu sehen ist in dieser Orientierung A,

ein nach unten offenes Rechteck B , ein nach links geöffnetes C und ein nach oben geöffne-

tes Rechteck D, dann kann man von H(1) zu H(2) kommen, in dem man rechts oben be-

ginnt und wie folgt arbeitet:

Zeichne D, zeichne Verbindungslinie, zeichne A, zeichne Verbindungslinie, zeichne A,

zeichne Verbindungslinie, zeichne B

Bedenkt man, dass die Drehungen um -90° bzw. 90° noch einzuarbeiten sind, dann ergeben

sich folgende Generatoren:

1. A der Initiator; ein offenes Rechteck

2. A --> + D + FA - F - A F + B + mehrere GeneratorenB --> - A - FB + F + BF - A -C --> + B + FC - F - CF + D +D --> - A - FD + F + DF - C -

3. α = 90°

Eine andere Sichtweise beruht darauf, dass die Figuren A und B bis auf Drehung identisch sind

und auch C und D dieselbe Figur sind. A und B werden gegen den Uhrzeigersinn durchlaufen,

während C und D im Uhrzeigersinn durchlaufen werden. Es könnten also zwei Generatoren rei-

chen, die X und Y heißen sollen. Dann gilt:

1. X der Initiator; ein offenes Rechteck

2. X --> - YF + X F X + F Y - zwei GeneratorenY --> + X F - Y F Y - F X +

3. α = 90°

Diese Dartellung ist u.a. zu finden bei:

http://home.t-online.de/home/Siegfried.Beyer

Dort finden sichauch weitere sehenswerte Beispiele zu L-Systemen.Welche der Darstellungen man verwendet ist egal. Ein Teil des Generators könnte also wie folgtaussehen:

Seite 49

Hilbertkurven

© Hans-Georg Beckmann 2004

A B C D

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

public void generatorA (int strecke, int tiefe){if(tiefe > 1)

{myTurtle.LI(90); // +generatorD(strecke,tiefe-1); // DmyTurtle.LI(90); // +myTurtle.VW(strecke); // FgeneratorA(strecke,tiefe-1); // AmyTurtle.RE(90); // -myTurtle.VW(strecke); // FmyTurtle.RE(90); // -generatorA(strecke,tiefe-1); // AmyTurtle.VW(strecke); // FmyTurtle.LI(90); // +generatorB(strecke,tiefe-1); // BmyTurtle.LI(90); // +}

else { myTurtle.VW(strecke); myTurtle.LI(90); myTurtle.VW(strecke); myTurtle.LI(90); myTurtle.VW(strecke); }

}// Ende von generatorA

Dabei ist die Varaible tiefe die Angabe darüber, welche Rekursionstiefe erreicht werden soll. Die

Variable strecke muss außerhalb der Rekursion festgelegt werden und darf sich in der Rekursion

nicht mehr verändern. Wechselt man von einer Rekursionstiefe zur nächsten wird, sich die Strek-

ke aber jeweils halbieren.

Die Ergebnisse sind bis zu einer Tiefe 8 noch gut am Bildschirm zu sehen. Danach ist strecke so

klein, dass die Kurve flächenfüllend wird ( was auch ihre besondere Eigenschaft ist ).

Seite 50

Hilbertkurven

© Hans-Georg Beckmann 2004

H(2) H(4) H(7)

Virtuelle Lehrerfortbildung imFach Informatik in Niedersachsen

Aufgabe:

Setzen sie das folgende L-System in ein Javaprogramm um:

1. F + + F + + F + + F + + F der Initiator

2. F --> F + + F + + F | F - F + + F Generator

3. α = 36°

Es entsteht "Plenta Plexity" nach Roger Penrose

Seite 51

Hilbert und Penrose

© Hans-Georg Beckmann 2004Virtuelle Lehrerfortbildung im

Fach Informatik in Niedersachsen