Einfache Datenaufzeichnung: Messwerte unmittelbar erfassen ...
einfache Rekursionen - VLiN · Weitere einfache Rekursionen Bis jetz haben wir direkte Rekursionen...
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