Video 2-3: Malen nach Zahlen, StdDraw
CS 210 – Algorithms and Data Structures (Summer 2026) · unit page
· YouTube
2026-04-22, 20:31
The transcript was generated automatically by YouTube's speech recognition and is offered as is. It may contain errors, in particular in concerning technical terms, names and formulas.
0:02 Im nächsten Teil schauen wir noch ein zwei andere ähm Teile von dieser Steinbibliothek an, die streng genommen gar nicht so richtig essentiell sind für das Modul, aber ich fand die so praktisch, um einfach kurz mal schnell sich ein Bild von was zu machen. In dem Fall auch im wörtlichen Sinne, ähm, dass ich Ihnen die kurz zeigen möchte. Da gibt's noch viel viel mehr auch an Hilfsmethoden, die mal schnell kurz ein einen Plot von der Funktion oder so malen. Können Sie natürlich mit 1000 anderen Tools machen, die heute wahrscheinlich schönste Variante ist irgen Jupiter Notebook, aber dann müssen Sie Python lernen. Äh vielleicht wollen sie das sowieso. Wenn Sie es rein in Java machen wollen, ist das nicht die schlechteste Variante. Und das Basislevel dazu, das schauen wir uns hier in dem Abschnitt noch kurz an. Also nur Text ist äh vielleicht nicht alles. Und einfaches äh grafisches Ausgabeformat ist dieses Standard Draw. Das kann im einfachsten Fall Punkte malen oder [räuspern] auch Linien. Es kann natürlich noch mehr auch so üblichen geometrischen äh Formen hat es direkt eingebaut.
1:09 ähm verweise ich sie jetzt nur auf die Website für äh es gibt da noch so ein paar Methoden, die diese Leinwand, auf der man malt, kann es äh konfigurieren, nicht kann man sie skalieren und so ein bisschen äh die Auflösung verändern. Das ist im wesentlichen alles, was das Ding tut. Ich will sie nicht davon überzeugen, dass das ausreicht, um viele einfache kurze Dinge mal schnell zu sehen. Und ganz ganz oft ist sich ein Bild zu machen im wörtlichen Sinn sehr viel äh schneller, um besser zu begreifen, was auch in Algorithmen vorgeht, als sich dann nur irgendwie äh Textbeispiele zu bauen.
1:52 Ein hübsches kleines äh Beispiel dafür ist ist dieses bisschen Code. Hier ist erklärt, was da passiert. Äh vielleicht kennen einige von Ihnen das auch schon. Ist ein ein bekanntes und gerne verwendetes Beispiel, aber in der Hoffnung, dass viele es noch nicht kennen, ist es einfach so schön. Also, wir verwenden einen Zufallsprozess, der Punkt für Punkt ein Bildchen malt und der ist schon ein bisschen verrückt. Wir fangen an mit im Wesentlichen einem äh gleichseitigen Dreieck. Also hier sind die Punkte. Das ist 00, das ist äh 10 und dann muss man eben ausrechnen Satz des Pythagoras und so kennen sie, kriegen Sie bestimmt hin, dass dieser Punkt eben dann bei ein/b und Wurzel 3/4 ist. Äh, dann haben wir hier dieses gedachte Dreieck. Mit diesen drei Punkten fangen wir an. Und jetzt wähle ich in jedem Schritt ein dieser drei Punkte zufällig aus. Und dann ich wähle ein Startpunkt in jedem der Hauptteil hier, das ist eine Schleife, nicht äh das springt zurück.
2:52 äh gutes altes ähm Pseudocode als Aufzählung mit werde ich wenig verwenden, aber hier, weil wir noch nicht offiziell über irgendwas anderes gesprochen haben, habe ich es mal so belassen. Der Hauptpunkt ist, wir wählen in jedem Schritt einen der drei Eckpunkte aus und springen dann zum Mittelpunkt zwischen dem aktuellen Punkt P, den wir am Anfang auf einen der Ecken setzen und diesem neuen gewählten Eckpunkt. Und da malen wir dann einen Punkt und dann machen wir das noch mal und so weiter und so fort. Also würde ich z.B. wenn ich hier am Anfang mit dem Punkt anfange und dann den hier wähle, wäre mein nächster Punkt hier. Und da bleibe ich jetzt auch sitzen. Dann würde ich vielleicht wieder diesen Anfangspunkt hier wählen und würde hier ein Punkt malen. Dann würde ich vielleicht diesen Punkt hier wählen. Das müsste ich irgendwie hier in die Mitte einen Punkt machen und dann vielleicht hier zwischen denen. Und das ist aber völlig zufällig, weil ich ja in jedem Schritt einen der Dreieckpunkte zufällig auswähle.
3:49 Also sollte das Bild, was da rauskommt, auch irgendwie relativ zufällig aussehen. Im Code ähm kann man das so umsetzen. Wir haben einen Eingabeparameter, also den lesen wir hier ein. Das ist das erste das erste Token aus der aus der Kommandozeile aus den Aufrufparametern. Das passen wir als int. Das ist die Anzahl Wiederholung, die wir für den Versuch für diese ähm für diesen zufälligen Prozess hier wählen. Dann sind hier ein paar Konstanten definiert. Also, ich habe die diese Zahl C, das ist das Wurzel 3/4 schon optimiert. Man kann die vier im Nenner aus der Wurzel rausziehen und außen durch zwei teilen. Macht jetzt auch keinen großen Unterschied, aber äh ist ein bisschen ähm vielleicht numerisch stabiler. Und dann haben wir für die drei Punkte die X und Y Koordinaten als kleines Array. Okay?
4:46 Äh, dann gibt's hier noch diese Methode, die die Größe von dem Punkt ähm festlegt. Wir haben den aktuellen Punkt P, das ist immer X und Y, die Koordinaten. Dann gehen wir die Trials äh alle durch. In jedem Schritt wählen wir einen der Eckpunkte zufällig. Dafür gibt's ähm z.B. für diese Methode. Sie kennen aber wahrscheinlich schon Java Util random mit Next in. Das wäre eigentlich die sauberere Version. Ich habe es hier so belassen, weil der Code so auch im Buch ist und an der Stelle haben sie noch nicht über diese anderen Methoden gesprochen. Also random selbst ist ist eine eine uniform verteilte reelle Zahl zwischen 0 und 1. So reell wie doubel halt sind nicht. Ähm, wenn ich das mal drei nehme und dann abrunde, habe ich auch eine Zahl zwischen 0, 1 oder 2. Eigentlich hätte man hier äh Das tut das gleiche. Dann berechnen wir den Mittelwert zwischen dem gewählten Eckpunkt und unserem aktuellen Punkt, indem wir das einfach koordinatenweise machen. Der Mittelpunkt, den ich hier auf dieser Linie zwischen meinem bisherigen Punkt und dem letzten hier gewählt habe, den bekomme ich, indem ich sowohl in X-Richtung als auch in Y Richtung den Mittelwert berechne. Ja, das machen die zwei und dann male ich diesen Punkt. Okay, soll wir das mal malen?
6:12 Ich hab das natürlich auch wieder vorbereitet. Also einmal hier der Code ähm sollte identisch sein zu was auf der Folie war. Dann wissen Sie natürlich Java Cass Path X4J Chaos Lup mit einer Hand tippen ist nicht so schnell tut mir leid. Das ist das Mikro.
6:54 Wenn ich das aufrufe, Aha, ich muss noch die Trials angeben. Wie viele soll wir machen? Ma mal 1000. Machen wir erstmal 100, dann geht's relativ schnell. Da sollte sich Aha, muss noch schade. Ähm, der Effekt wäre noch cooler, wenn das jetzt direkt aufgehen würde.
7:24 Mit Steuerung C das abbrechen, dann können wir es noch mal machen. Äh, es taucht erst auf, wenn das fertig gemalt hat. Das ist zu schnell. Na ja. Ähm, machen es noch mal und jetzt mal ein paar mehr Punkte, dann sehen Sie auch die Evolution vielleicht ein bisschen mehr.
7:47 Und dann sieht man, das ist irgendwie gar nicht so richtig zufällig, was da rauskommt. Sie kennt das Ding vielleicht, das heißt Pinski Triangle. Ähm an vielen Stellen auch verwendet. M könnte jetzt die Kernvas ein bisschen größer machen. Im Anbracht der Zeit. Lassen Sie mich das mal überspringen. Aber Sie sehen, ähm wenn man genügend Punkte malt, dann ist das Ergebnis eigentlich deterministisch. Ist schon vorher bestimmt, wie das aussieht. Und das ist erstmal nicht klar, dass das so ausgeht, wenn ich irgendwelche zufälligen Prozesse mache. In dem Fall ist es aber so. Und das ist ein schönes Beispiel, wo ähm das Bild einem sofort was äh zeigt, ganz klar und offenbar, was man mathematisch sich erstmal erarbeiten müsste. Und damit man weiß, was man beweist, sollte man erstmal wissen, was was Phase ist. Deswegen ist hier einfach das Bild malen sehr viel schneller. Okay, das war mal nach Zahlen Schritt 1. Wenn man jetzt schon am Spielen ist, dann kann man auch feststellen, dass was wir hier gemalt haben, dieses Dreieck, das ist eigentlich ein Spezialfall von dem allgemeinen Vorgehen. Iterated Function Systems. Wir haben immer einen aktuellen Punkt. In jedem Schritt wählen wir eine zufällige Funktion aus, die aus diesem aktuellen Punkt einen neuen Punkt macht. In unserem waren das drei Funktionen, nämlich bilde den Mittelwert zwischen dem linken unteren Eckpunkt oder bilde den Mittelwert zwischen dem Punkt und dem rechten unteren Endpunkt oder bilde den Mittelwert mit dem oberen Punkt aus dem Dreieck. Dann waren das eben diese zwei einfachen Funktionen für ähm die X und Y Koordinate. Und wir haben aus den drei Funktionen Uniform ausgewählt, alle mit Wahrscheinlichkeiten Drittel.
9:34 Dementsprechend könnte man, was wir eben gemacht haben, so darstellen. Es gibt diese drei Funktionen. Wahrscheinlichkeit ist jeweils ein Drittel. Und wenn Sie sich überlegen, was die ähm was der Mittelwert ist, wenn ich den die Koordinaten für die drei Punkte einsetze, dann kommt eben das hier raus. Also z.B. Die zweite Funktion macht aus der x-Koordinate des aktuellen Punktes, als neue X-Koordinate die Hälfte von x +/ als neue y Koordinate die alte Y Koordinate durch 2. Okay, das ist nichts anderes als Mittelwert zwischen den drei Punkten eingesetzt mit den konstanten Koordinaten der drei Punkte. Worauf ich hier hinaus will, ist das sind alles ähm einfache lineare Funktionen in X und Y. hier sogar als Spezialfall in der Funktion hier kommt nur X vor, hier kommt nur y vor. Das ist ein bisschen zu streng. Äh im Allgemeinen erlauben wir, dass da irgendeinen ähm eine lineare Funktion in X und Y vorkommt oder eine affine Funktion. Um eine affine zur Funktion zu bekommen, haben wir noch so ein Konstanten Offset.
10:37 Das ist ein bisschen, wenn man möchte, könnte man das als lineare Algebra darstellen und dann sieht das so aus. Äh, der einzige Vorteil davon ist, dass man dann kompakt diese Funktionen beschreiben kann. Also, wenn diese Funktionen lineare Funktionen sind, dann kann ich alle solche Funktionen darstellen als die Matrix für A, das ist die für X, und die Matrix B für die y Koordinaten. Dann beschreibt das die Funktion hier, das konkrete Beispiel für eben diese Tabelle. Und ich muss noch angeben, in welcher mit welcher Wahrscheinlichkeit ich die drei Funktionen auswähle.
11:15 Alle noch bei mir? Ähm, wenn man das so gebaut hat, dann kann man mit gar nicht viel mehr Code dieses ganz allgemeine Problem implementieren, das jetzt zwei Schritte hat. Zuerst lesen wir diese Zahlen ein, die zwei Matrizen und diese Wahrscheinlichkeitsverteilung und dann machen wir die Simulation wie eben mit dem Punkte malen.
11:40 Das ist ein ähm schöner Anlass, um noch mal eine andere Klasse aus dieser Standardbibliothek zu zeigen. Es gibt ein Standard Array IO, das einfach Arrays und Matrizen nach einem bestimmten Format ein und auslesen kann. Z.B. ist hier. Das ist diese Eingabe, die das Sopinski Dreieck wieder generiert. Ähm für Arrays, also hier diese dieser Aufruf ähm ein 1D äh eine 1D Matrix oder ein Vektor ähm gebe ich zuerst an, wie viele Zahlen kommen da jetzt und dann kommen so viele Zahlen. Das wäre das, was hier bei Distribution rauskommt. ist ist also wenn dieser Aufruf mit der Eingabe auf Standard in ausgeführt wird, ein Vektor mit drei Zahlen drin, drei Doubles, diese Zahl, diese Zahl, diese Zahl um und bei ein Drittel so gerunde, dass sie sich zu einsieren. Okay?
12:40 Äh für 2D Vektoren oder Matrizen, 2D Arrays und Matrizen gibt's dieses Format. Also der Aufruf würde dann dazu passen. Ich sage zuerst, wie viele Zahlen und Spalten und dann kommen so viele Zahlen, dass ich die hier so als Matrix gerückt habe. Es ist einfach nur mit Whitespace getrennt. Das ist nur damit es schöner lesbar ist. Und dann kriegen wir hier die ähm die 2D Arrays raus mit diesen jeweils neuen Zahlen und dann führe ich wieder so viele Trials aus wie in der im ersten Argument angegeben. Das heißt, auch hier wieder ähm Eingabe liefere ich einmal mit einem Aufrufparameter und dann über Standard in. Beides gemischt. Werden gleich sehen, warum das bequem ist. Äh, dann mache ich diese Berechnung. Die sieht so aus wie vorher. Der einzige Unterschied ist, dass ich jetzt allgemeineren Aufruf hier für die ähm Zufallszahl habe.
13:42 Das ist die letzte Standardbibliothek, die ich Ihnen noch äh zeigen wollte. Random stdd Random hat eine Methode discrete, also die eine diskrete Wahrscheinlichkeitsverteilung sampelt. Da kann ich also einen Vektor angeben mit den Wahrscheinlichkeiten und dann bekomme ich eine Zahl zwischen 0 und der Länge -1 raus. gewählt entsprechend dieser Wahrscheinlichkeiten. Das ist genau, was wir hier für die Funktion wollen. D bekommen wir den zufälligen Index der Funktion, die wir jetzt verwenden sollen und den verwenden wir dann hier für die passende Linie für die passenden Koeffizienten der linearen Funktion.
14:20 Dann malen wir den Punkt. Ähm ein Implementierungsdetail ist hier noch dieses Double Buffering und dann show. Das hat damit zu tun, dass wenn Sie vielleicht sich erinnern, wie das eben mit dem Dreieck aussah, da kommt ein Punkt nach dem anderen. Man kann fast zugucken. Das war da auch Absicht. Wir wollten ja zugucken, aber das ist schon ziemlich langsam. Äh Computer können deutlich schneller malen, aber eben nicht, wenn ich sie nach jedem Punkt malen dazu zwinge, das Ergebnis in die Grafikkarte auszugeben und anzuzeigen.
14:51 Äh, die Computergrafiker unter Ihnen wissen das vielleicht. Äh, wie macht man das, wenn man schnellere Dinge bauen will, Computerspiele und sonstiges? Man verwendet zwei Puffer, einen, der den aktuellen Bildschirminhalt anzeigt, der auch so direkt in der in der Grafikkarte dann verwendet wird und einen zweiten, auf den ich Änderungen drauf schreibe und dann sage ich mit einem bestimmten Befehl so und jetzt tauschen. Den der im Puffer ist, wird dann angezeigt und der andere wird zum Puffer, den ich ändere. Deswegen heißt das Double buffering. Damit kann man einfach das malen sehr viel schneller machen. Ich sehe dann aber erst die Änderung, wenn ich das nächste Mal Show aufrufe.
15:36 Diesmal ist der Code ähm, den ich hier habe, ein ganz kleines bisschen anders. Der Grund ist, weil man so wie das auf den Folien war, nur ganz am Ende einmal das Bild zu sehen bekommen würde. Ja, also hier nachdem was ich eben gesagt hatte mit Double Buffering, alles was wir hier malen, die ganzen Iterationen sehen wir erst, wenn ganz am Ende nach allen Iterationen Show aufgeruft wird. Für den Showffekt hier in der Vorlesung ähm wollte ich, dass man ein bisschen was vorher sieht. Das heißt, ähm, hier gibt's noch mal innen drin einen kurzen Effekt. Nach allen nach 100 Iterationen wird einmal Show aufgerufen. Ansonsten ist der Code der gleiche wie auf den Folien.
16:24 Gut, kompiliert hatte ich es vorhin schon. Sie wissen ja, Class Path und so weiter kennen Sie langsam auswendig. Äh, dann muss ich ifs eingeben und die Anzahl Iteration. Ähm ah, zweite Änderung im Code. Ich habe die Canvas größer gemacht. Das heißt, wir kriegen ein höher aufgelöstes Bild. Wenn ich das nur so aufrufe, müsste ich jetzt von Hand die Zahlen eingeben. Das könnte man natürlich machen, aber da habe ich keine Lust zu. Deswegen habe ich das vorbereitet als Datei.
16:56 Sehen an sich, das ist die Textdatei, der Inhalt, der auch auf den Folien stand. Und dann kann man das mit diesem kleinerzeichen hier rein typen. Das heißt, jetzt wird Standard in für diesen Prozess ersetzt durch den Inhalt aus dieser Datei.
17:11 Beim ersten Aufruf wird es wahrscheinlich wieder nicht. Ah, doch, aber ich habe es größer gemacht. He, ich sehe nichts. Vergehen wir mal eben. Und so langsam langsam erscheint da was. Es ist sehr äh klein, das heißt, wir müssen da mehr Aufrufe mehr ähm Wiederholung machen.
17:50 was habe ich falsch gemacht? Ja, ich habe das äh in den Dateienamen eingefügt. Das geht natürlich nicht. Okay, dann sehen Sie jetzt steht das gleiche Bild nur in Größe aufgelöst. Ähm, dazu ist nur folgende Änderung hier nötig. Sie setzen einfach die Canvas Size auf größeren Wert.
18:20 Der Standard ist 512 auf 512. Wenn man aber jetzt diese allgemeine Funktion hat, dann kann man auch andere äh Zahlen da reinfüttern. Z.B. sowas. Das ist eine andere Wahrscheinlichkeitsverteilung. Ich habe jetzt drei Funktionen, die mit diesen seltsamen Wahrscheinlichkeiten gewählt werden. Meistens die erste, ab und zu die anderen beiden. Und ich habe diese anderen linearen Funktionen, den man jetzt auf den nächsten Blick nicht wirklich ansieht, was da abgeht, ne? Äh, das Schöne ist, wir müssen das ja nicht theoretisch lösen. Wir können ja einfach ein bisschen spielen und das hier mal äh ausführen und dann gibt es irgend so einen Spiralenbild mit irgendwelchen fraktalen sich selbst wiederholenden Mustern. Äh, ein anderer Klassiker ist der Barnsley Baren. Das sind diese vier Funktionen in dem Fall. Und dann sieht das eben so aus.
19:29 Den haben Sie bestimmt auch schon gesehen. Das ist so Klassiker. Genau. Gut, genug gespielt. Also sehen, mit sehr wenig Code kann man irgendwie schnieke Sachen malen. Ähm und man lernt ein bisschen was über lineäre Algebra dabei. Hier gibt's noch ein paar andere Beispiele. Da gibt's noch mehr auf der auf der Booksite. Können Sie ein bisschen, wenn Sie Langeweile haben oder irgendwo ein Bus feststecken, können Sie sich noch ein paar andere anschauen. Äh und dann kann manich noch so ein bisschen diese philosophische Frage stellen, gibt's da irgendwie, dass diese Sachen so nah an irgendwelchen natürlichen Strukturen aussehen? Ähm, hat das was darüber zu sagen, was in der Natur passiert oder hat irgendwie gibt's gibt's berechnende Aspekte in der Natur? Gibt's da philosophischen Zusammenhang? Äh, das ist natürlich eine Frage, die ich Ihnen auch nicht beantworten kann. Ähm, was natürlich klar ist, dass jede jede Art günstig irgendwelche schönen Bilder zu generieren, die natürlich aussehen, Anwendung hat, wo immer man sowas braucht.
← Video 2-2: algs4 Library, StdIn, StdOutVideo 2-4: Mehr zu entdecken, StdAudio →