. . .
Musik Musik Musik Musik Musik Tschüss. So. Wollen wir?
Wollen wir? Wollen wir? So, Wonja
Ah, der Damm, heutige Vorlesung. Ich bin eben
gerade schon auf den ersten Fehler den Folien hingewiesen worden,
das soll Kapitel 2 heißen, nicht Kapitel
3. Ich hoffe, das ist ein kleiner Kleinigkeiten.
Ich hoffe, das ist der einzige Fehler. Heute,
also wir haben ja letztes Mal irgendwie Ohnotation, suchen,
sortieren so ein bisschen gemacht.
Noch lauter. Ich habe das Gefühl, ich schreie mich
selbst an.
Besser. Okay, ähm, boah. Genau,
letztes Mal bei U-Notation gemacht, suchen, sortieren und hatten
noch so im Ausblick drin, dass wir gesagt haben,
dass mit den rekursiven Algorithmen, da hilft das im Moment noch nicht.
Dieses irgendwie Schritte zählen, das ist da irgendwie umständlich,
weil man ja irgendwie durch die rekursiven Aufrufe irgendwie die Methode
immer wieder aufruft und man weiß nicht so genau,
wie oft man sie aufruft,
das führt irgendwie zu Problemen
Das war das eine, was wir noch offen gelassen haben und das andere,
was wir offen gelassen haben, war,
wie beweist man eigentlich, dass so ein Algorithmus korrekt ist?
Also gar nicht jetzt die Laufzeit,
sondern überhaupt, dass der von der Funktion das tut,
was wir hoffen, dass er tun soll.
Aber sowas wie der linearen Suche war das irgendwie noch ziemlich offensichtlich.
Bei anderen Algorithmen ist das nachher nicht mehr so offensichtlich.
Also bei dem Insertion Sword da, den habe ich
da hingeschrieben, weil wir den gleich nochmal brauchen.
Da ist es deutlich weniger offensichtlich, dass der tatsächlich das tut,
was er tun soll. Das muss man irgendwie beweisen.
Und genau um die zwei Sachen soll das heute gehen,
einmal Korrektheit von Algorithmen, zumindest mal für einen Algorithmus zeigen,
dass er korrekt ist.
Und die Laufzeitanalyse rekursive Algorithmen
Genau, und wegen dieser Laufzeitanalyse ist die Vorlesung heute
auch nochmal ähnlich doll mathematisch wie letztes Mal.
Das wird nachher ein bisschen softer, so die ersten zwei Vorlesungen,
ist immer relativ viel Mathematik. Der Anfang heute ist ein
ziemlich dicker Wiederholungsblock, das dünnt sich später auch aus.
Ich mache das am Anfang meistens so, dass ich viel wiederhole,
damit möglichst viele halt die ganzen Basics mitkriegen,
weil man gerade die ja später braucht und später wiederhole ich deutlich weniger.
Da sage ich dann einfach nur das und das haben wir gemacht,
aber für dieses Mal wollte ich nochmal recht ausführlich wiederholen.
Also was haben wir gemacht
Eins der Hauptziele in der Vorlesung ist irgendwie Algorithmen zu bewerten bezüglich
ihrer Laufzeitkomplexität und ihrem Platzbedarf. Und dann haben wir gesagt,
wir nehmen solche Funktionen hier, F von N nach R,
Ende ist irgendwie die Länge der Eingabe oder eben die Größe,
diese die Anzahl der Kenngrößen da.
Und das bilden wir ab auf die Laufzeit, also auf die Anzahl der Schritte,
die wir brauchen bei einer Eingabe dieser Länge im Worst Case.
Dann haben wir diese Unnotation kennengelernt,
mit der man dann nicht, also mit der man,
wo er so Aussagen machen kann, wie der Algorithmus läuft,
den O von Endquadrat statt,
irgendwie zu sagen,
der läuft in Endquadrat minus 3N plus 5
oder irgendwie sowas
Das interessiert einen dann nicht mehr so sehr, sondern halt einfach das Wichtigste in dem Polynom sozusagen aussagen zu können. Ja,
und die Wichtigen waren eben groß, oh, Groß,
Omega, Großtäter, Groß-Oder war so die Idee,
die Funktion, die in Groß-O von Ge sind,
das sind die, die kleiner gleich sind, die,
die in Omega-G sind, das sind die,
die größer gleich sind und die, die in Täter sind,
das sind die, die so ungefähr gleich sind.
Da hatten wir noch die nicht ganz so wichtigen,
dieses Klein-O und das Klein-Omega, das sind die,
die echt kleiner sind und echt größer sind.
Dann hatten wir als Alternative diese Liebesschreibweise mit der man meistens einfacher rechnen kann,
als wenn man hier irgendwie versucht,
so ein C anzugeben und so ein N-0,
sodass dann irgendwie für alle Enden, die größer sind,
diese Ungleichung gilt.
Da ist es meistens einfacher, mit dem Liebes zu rechnen und zu gucken,
ob dieser Bruch hier kleiner wird als unendlich,
wenn man N gegen unendlich streben lässt.
Das ist dann meistens einfacher. Ja,
dann habe ich hier noch jetzt dazu genommen,
dieses FNS sind Täter von G, genau,
dann werden da eben irgendwie so eine positive Konstante rauskommt.
Wir hatten ja letztes Mal, es ist genau dann ein Täter,
wenn es sowohl ein Großohr ist, als auch in Großomega.
Und wenn es in Großohr ist,
muss es kleiner sein als unendlich und wenn es in Großomega ist,
muss es größer sein als null. Das heißt,
wenn es gegen so eine konstante C geht aus R plus,
dann sind beide Bedingungen erfüllt,
also es ist dann ein O und enormega,
also ein Täter
Ja. Und jetzt hatte ich,
hatte ich auch rumgeschrieben und so einen kleinen Text da geschrieben.
Dieser Satz von El Hobby Tal. Oder wie man das ausspricht.
Ich hatte leider keinen Französisch. Ich glaube, El Hobby
Tal ist richtig. Dieser Satz macht eine Aussage darüber,
wenn man diese Liebesberechnung machen will. Und das quasi mit
diesen Funktionen F von En und G von En nicht funktioniert.
Wenn die beispielsweise beide gegen unendlich gehen. Also sowas wie
im Zähler steht, Lugarithmus von N und im Nenner steht N.
Da kann man irgendwie nicht kürzen und nichts.
Beide gehen gegen unendlich
Kommt man erst mal nicht weiter. Und dann sagt dieser Satz,
dass man, wenn beide gegen unendlich gehen,
wenn denn N gegen unendlich geht,
dass man dann mit den Ableitungen weitermachen kann.
Also wenn ich zwei Funktionen F und G habe und beide
gehen entweder gegen null oder beide gehen gegen unendlich,
wenn N gegen unendlich geht,
dann darf ich mir den Liebes angucken von den beiden Ableitungen.
Und wenn der existiert, dann existiert eben auch der Liebes von F von N
durch G von N und beide haben den gleichen Wert.
Sprich, was ich mache ist,
ich leite beide Funktionen einmal ab,
gucke mir dann den Bruch an und berechne den Liebes
Wenn da jetzt was rauskommt, dann weiß ich,
okay, das ist der gleiche Limis wie der,
den ich ursprünglich mal gesucht habe.
Und unter Umständen muss ich das mehrmals machen. Also wenn ich hiermit auch
noch nicht weiterkomme mit dem Limis von F-Strich von NG-Strich von N
, dann muss ich vielleicht nochmal ableiten und nochmal ableiten.
Genau. Und der Satz, so wie er da steht,
für unsere Funktion ist der praktisch immer anwendbar.
Also hier ist ja noch die Einschränkung, die Ableitung von
G von N soll ungleich null sein für alle N.
Das gilt eigentlich immer für alles, was wir machen wollen.
Und dann noch so als Anmerkung, so wie er dasteht,
ist der Satz nicht ganz exakt formuliert.
Also so wie es da steht, gilt es,
aber der Satz ist eigentlich noch ein bisschen allgemeiner,
dass die auch beide gegen so ein WRA,
also gegen den Grenzwirt in so einem Intervall gehen dürfen.
Und dann gilt das auch, wer das mal nachlesen möchte,
steht in den meisten Analysusbüchern aus der Mathematik drin.
Wir wollen es halt einfach nur benutzen, wir wollen einfach nur sagen,
okay, wenn ich da jetzt irgendwie nicht weiterkomme,
dann bilde ich die beiden Ableitungen und gucke,
ob ich damit weiterkomme.
Beispiel, was auch in diesem kleinen Text drin war,
wenn ich jetzt irgendwie zeigen möchte,
dass der Logorithmus von N in O von Wurzel 3 von N ist.
Jetzt müsste ich den Limes von Logarithmus N durchwurzel 3
von N bestimmen. Kann ich irgendwie nicht machen,
weil das geht gegen unendlich,
hilft mir nicht
Und jetzt sagt der Satz von El Hobby Teil,
aber naja, wenn N ging, unendlich geht,
dann geht ja sowohl Logarithmus von Enggegen unendlich,
als auch Wurzel 3 von N geht gegen unendlich.
Dann darf ich also, um das hier zu bestimmen,
Logarithmus von N durch Wurzel 3 von N, darf ich beide Funktionen ableiten.
Hier drunter steht, was die Ableitung ist, also wenn ich
den Logarithmus von denen ableite, dann ist das eins durch N.
Und wenn ich Wurzel 3 von denen ableite, Wurzel 3
von N ist das gleiche WN hoch, ein Drittel.
Und wenn ich das ableite,
ein Drittel mal N hoch, ein Drittel minus eins,
also N hoch minus zwei Drittel und dann kommt hier
das daraus
Und wenn ich mir die dann da beide hinschreibe,
Logarithmus von Enden wird eins durch Ende, dann das ist das N hier.
Und das Wurzel 3 von N abgeleitet wird.
Ja, Kram. Und damit kann ich dann rechnen.
Dann mache ich ganz normal weiter. Hier habe ich Endhoch,
zwei Drittel, da habe ich N hoch einstehen,
dann bleibt da unten, also Ende hoch ein Drittel,
übrig, wenn ich kürze, das ist wieder die dritte Wurzel von Ende.
Und da kann ich jetzt sehr schön den Liebes bestimmen.
Das geht jetzt, der Nenner geht gegen unendlich,
also geht das gegen Null.
Und dann bin ich fertig
Hattet ihr den in Mathe? Zweites Semester, halt die? Genau,
dann, da waren wir,
da wollte ich da nochmal diese Merkhilfe, ne,
FNO von G, wenn F kleiner gleich G ist,
FN Omega von G,
wenn F größer
gleich G ist und so weiter
Und da nochmal, was wir halt machen wollen,
wenn wir einen Algorithmus bezüglich seiner Laufzeit oder seines Platzbedarfs analysieren wollen.
Wir überlegen uns erstmal irgendwie so eine Kenngröße,
die Anzahl der Knoten im Grafen,
die Anzahl der Elemente im Array, irgendwie sowas,
bezüglich der wollte bestimmen wir dann Laufzeit und Speicherbedarf,
also Speicherbedarf, wenn uns das interessiert,
in vielen Fällen interessiert uns das in der Vorlesung hier noch gar nicht,
aber es gibt später Fälle, wo er das interessiert.
Und dann guckt man eben nochmal verfälscht,
dass das Ergebnis, das war so diese Geschichte mit,
wo wir vorhin gesagt haben,
so die Größe einer Zahl, dass es eben nicht,
oder der Wert einer Zahl,
das ist keine so gute Kenngröße für die Laufzeit eines Algorithmuses
Ja, das zur U-Notation. Und dann hatten wir Suche und Sortieralgorithmen,
Suchalgorithmus gegeben, irgendwie so eine Menge von N-Objekten und ein
anderes Objekt P. Ist das da drin oder nicht?
Genau, dann hatten wir als einen Algorithmus das ganz primitive
so lineare Suche. Ich gucke mir jedes Element an,
gucke, ob das übereinstimmt mit dem,
was ich suche und verletze ja, sage ich,
liefere ich wahr zurück und falls nicht,
liefere ich falsch zurück
Sinnvolle Kenngröße, die Anzahl der Elemente im Array, also das N.
Und dann kann man sagen, der Algorithmus hat die Laufzeit-O von End,
ich gucke mir jedes Element einmal an, also bin ich irgendwie ein O von End. Binäre Suche,
das war so diese Idee gegeben, so ein Array,
dass Array immer weiter zu halbieren, zu gucken,
ist das mittlere Element, ist das kleiner oder größer als das,
was ich suche, falls es kleiner,
suche ich in dem rechten Element des Arrays weiter,
weil es größer ist, suche ich in dem linken Element des Arrays weiter.
Und wenn es genau das Element ist, was ich suche,
bin ich fertig. Kann man auch wieder sagen,
sinnvolle Kenngröße, Länge des Arrays, Laufzeit dann O von Login,
weil ich immer weiter halbiere und Genau,
dann gibt es da so diese Einschränkungen,
dass man sagt, dafür muss das Arry sortiert sein,
ich muss eine Ordnung auf den Elementen haben,
sonst kann ich solche Vergleiche hier nicht machen,
ob AM kleiner ist als P oder nicht und sowas.
Also Ordnung brauche ich, sortiert muss es vorliegen und ich brauche einen direkten Zugriff auf die Elemente.
Das ist ja auch nicht in jeder Datenstruktur gegeben.
Also so wie es hier ist, mit den Arrays,
da geht das, wenn ich eine Datenstruktur habe,
die mir keinen direkten Zugriff erlaubt, funktioniert das wieder nicht,
weil ich dann nicht auf das Element direkt in der Mitte zugreifen kann.
Oder halt nur total umständlich, wenn ihr euch überlegt,
ihr habt eine lineare Liste und ihr geht da einmal rüber,
um die Länge zu bestimmen und dann geht ihr nochmal rüber,
bis ihr bei mittleren Elementen seid und halbiert das da und so,
dann wird das Schnarch langsam.
Dann ist das nicht mehr effizient
Da steht es nochmal, was man alles,
also lineare Suche hat quasi keine Anforderungen,
außer dass ich irgendwie an die Elemente rankommen muss und dass ich
irgendwie so einen Equals-Operator haben muss, um herausfinden zu können,
ob das Element das ist, was ich suche.
Und bei der Billärensuche ist eben deutlich mehr nötig,
was ich haben muss. Vor allem eben dieses,
dass ich einen direkten Zugriff haben muss und dass es bereits sortiert vorliegen muss.
Eine Ordnung habe ich ja meistens auf Elementen, die mich interessiert,
aber irgendwie, ich muss die Elemente schon sortiert haben.
Überleitung zu dem Thema sortieren, das heißt,
ich muss die Elemente sortiert haben, jetzt kann ich mir überlegen,
wie ich sie sortiere.
Wir geben irgendwie eine Sequenz von Objekten,
in dem Beispiel, da oben steht jetzt von Zahlen,
das funktioniert auch mit irgendwie N-Objekten
Brauche auch wieder eine kleine größere Operation oder sowas,
sonst kann ich dir nicht sortieren. Und gesucht ist jetzt
eine Permutation, genau diese Objekte, sodass sie sortiert sind.
Und dann gab es noch diese beiden Begriffe.
Okay, ich rücke mal weiter. Dann gab es noch
diese beiden Begriffe stabil. Wenn man die Reihenfolge Zweierelemente,
die den gleichen Wert haben, wenn die gleich bleibt,
also wenn ich zweimal die fünf habe,
einmal als drittes Element, einmal als sechstes Element,
dann soll die fünf,
es gucken übrigens mehr Leute bei dir zu
als bei mir
Die komplette dritte Reihe hat eben alles so nach da geguckt. So,
genau, stabil, wenn ich zweimal die fünf habe,
einmal als drittes und einmal als sechstes Element und ich
nachher bei der Sortierung auch möchte, dass das Element,
was vorher vorne war, dass das weiterhin vorne ist,
dann nenne ich so ein Element so eine Sortierung stabil und in place eben,
wenn ich keinen zusätzlichen Speicherbedarf brauche.
Also höchstens so für höchstens konstant viel Speicherbedarf,
dass ich irgendwo meine tempoäre Variable habe oder so, okay,
aber halt nicht, dass ich das komplette Area nochmal duplizieren muss.
Genau. Und andere schreibt, weil sie hier irgendwie Institut,
liest man auch manchmal so in Büchern
Dann hatten wir das, sortieren mit Maximumsbestimmung, hier bei dem Algorithmus 4,
da sucht man das Maximum in so einem gegebenen Array,
man nimmt zuerst an,
dass das Element am Index 1 das größte ist und dann geht man sie alle durch,
alle, die noch übrig sind, guckt,
ob das größer ist als das, wovon man gerade annimmt,
dass es das Maximale ist und falls ja,
sagt man, wenn AI größer ist als am Max,
dann sagt man, okay,
jetzt ist das neue maximale Element ist jetzt eben ein Index I und dann geht man halt weiter durch,
bis man das größte gefunden hat,
dauert O von End viele Schritte
Und dann kann man hier oben eben von N bis 1 runtergehen,
man bestimmt immer das größte Element, in dem Arry Max.
Und wenn man das gefunden hat,
dann setzt man das eben an die Stelle BN,
BN minus 1, BN minus 2 und so weiter.
Also man führt quasi das RAB von hinten auf.
Das größte kommt ganz nach hinten, das zweitgrößte Dan und so weiter.
Und dann setzt man das Element, von dem man gerade rausgefunden hat,
das Maximum ist, das setzt man jetzt auf null,
damit das bei der nächsten Maximumsbestimmung halt nicht gefunden wird.
Alles unter der Annahme,
ich habe eine Menge von natürlichen Zahlen,
sonst muss ich da irgendwie statt null,
not a number oder null oder irgendwie sowas nehmen,
dass das
halt hier nicht gefunden wird als maximales Element
Geht auch mit Minimum, dass ich irgendwie hier statt das Maximum,
das Minimum suche und dann hier halt nicht von Ende runtergebe es eins, sondern von eins hochgebe es N.
Und jetzt ist hier ja aber irgendwie doof,
also mal davon abgesehen, es funktioniert,
es ist okay, es ist auch schnell implementiert,
es läuft in O von Endquadrat, doof ist noch,
also erstmal ist die Laufzeit vielleicht doof und das andere,
was doof ist, hier dieses,
dass ich zusätzlich dieses RAB brauche,
geht das auch inplace.
Also ohne so ein RAB komme ich alleine mit dem RAR
aus. Aber weiterhin mit dieser Idee der Maximumbestimmung,
nicht jetzt irgendwie sagen, hui,
ich nehme total anderen Algorithmus oder so,
sondern weiter mit dem
Genau. Er hat gerade gesagt, man sucht sich das
Maximum und das swappt man dann mit dem anderen Element einfach.
Dann ist das Maximum ganz hinten. Ja, anders.
Man sucht das Maximum und man fässt das letzte Element an.
Die beiden swappen, man nennt das das Maximum ganz hinten und das,
was vorher letztes Element war, ist irgendwo anders.
Und als nächstes sucht man jetzt nicht das Maximum mit dem ganzen Array,
sondern in dem Array 1 bis N minus 1. Und dann swappt man das,
was man jetzt gefunden hat mit dem N minus 1. Element
und immer so weiter
Da steht's. Also auch wieder von N bis 2 gucke ich jetzt immer,
was ist das Maximum, in dem Array von 1 bis eben I,
also am Anfang in dem ganzen Array,
dann in dem Array bis N minus 1,
in dem Array bis A minus 2,
in dem Array bis N minus 3 und so weiter.
Maximusbestimmung geht genauso. Und wenn ich das Maximum gefunden habe,
dann tausche ich halt das Element an der Stelle A-N mit diesem Maximum aus,
dann das Element an der Stelle A-N minus 1 mit diesem Maximum und so weiter.
Dann bin ich in Plays, brauche weiterhin O von Endquadrat
viele Schritte. Das ist zwar schneller als der vorherige Algorithmus,
der vorherige hat ziemlich genau irgendwie zehnmal Endquadrat viele Schritte gebraucht,
der hier braucht ja bei der Maximumsbestimmung hier im Worst Case erst Endschritte,
dann in minus ein Schritte,
in minus zwei Schritte,
in minus drei Schritte und so weiter,
so wird er schneller
Aber von der asymptotischen Komplexität ist der weiteren ON-Quadrat.
Weil das ist jetzt irgendwie ein Endquadrat, minus Ende halbe ist oder so,
das tut sich nicht so sonderlich viel, ja.
Wenn ich das jetzt tatsächlich in der Familie mal beschreiben würde,
dieses Carry-Fonds, das ist das.
Ja. Ich würde wieder sozusagen Selbstständigung davor sich das ein
zweites Array machen, ich würde gar nicht viel sparen.
Die Frage ist gerade, wenn man das jetzt implementieren würde,
wie man damit denn umgeht, dass man,
ich würde da immer nur so ein Teil des Arrays übergibt.
Man will ja jetzt das nicht so machen,
also wenn, das hängt halt von der Programmiersprache ab,
wenn die Programmiersprache so ist,
dass sie das immer komplett klont,
dann bringt das gerade nicht so viel mit dem Inplace,
dann klone ich hier immer und habe ständig
einen kompletten Klon davon rumflattern
Üblicherweise werden aber irgendwie nur Pointer auf den Array-Anfang übergeben.
Also was man machen kann, ist,
dass man irgendwie die Methode nicht so hier schreibt wie hier,
sondern dass man quasi den Pointer auf den Anfang des Aris übergibt und den Index bis wohin man wandern will.
Da sagt man, im RAR interessiert mich jetzt der Bereich von 1 bis i.
Und dann hat man das. Ja, sehr schöne Frage. Der andere,
den wir hatten, Insearchance Hard,
den du noch einmal so ganz kurz,
dass ich ihn einmal kurz seht,
aber auch in O von Endquadrat, auf dem kommen wir nachher,
wenn es um die Korrektheitsbeweise geht, nochmal genauer zu sprechen,
oder dass sie den da für die Wiederholung einmal kurz seht.
Wir kommen da
gleich genauer zu
Ja, und das waren die Laufzeiten, die wir hatten,
lineare Suche in Uf von Enbinäre Suche Ohr von Login,
Maximumsbestimmung O von N, Minimumsbestimmung, auch in O von N,
sortieren mit dieser Maximumsbestimmung dann in Uf von Endquadrat und Insearch
and Sort eben auch in O von Endquadrat.
Und als Kennzahl hat man immer die Anzahl der Elemente genommen,
die man sortieren will oder eben die Anzahl der Elemente,
in dem Area, in dem man gerade sucht.
Genau. Dann da nochmal die Anmerkung zum Lesen hier,
dass man eben Dass diese O-Notation zwar irgendwie konstanten verschluckt und
dass das auch quasi für alle Fälle,
die in der Praxis auftreten, ist das völlig in Ordnung.
Da ist es wirklich so, dass so ein Algorithmus in
O von N schneller ist als einer in O von Endquadrat.
Aber es gibt so Fälle, die man irgendwie konstruieren kann,
sowas wie den hier irgendwie, zehn hoch,
sechsmal N und zehn hoch, minus zehn mal zwei hoch N.
Da ist dann eben dieser O von N-Algorithmus eben doch
lange Zeit nicht cooler als der O von zwei Hochenden-Algorithmus,
sondern erst bei Eingabegrößen, die irgendwo weit jenseits gut und böse liegen.
Naja, wobei, zehn Uhr minus, naja,
doch, das dauert eine Weile,
bis er das einholt
Also das nur so als Aufhol, als Erinnerung daran,
dass diese Unnotation zwar sehr gut ist in der Praxis und dass man das auch sehr gut benutzen kann,
um Algorithmus zu bewerten, dass die Aussage vom Kollegen irgendwie,
ich habe jetzt einen Algorithmus, der löst das Problem schneller,
der ist nur noch in Enma-Login, statt in O von Endquadrat,
dass das im Allgemeinen halt wirklich dann bedeutet, der schneller,
aber das ist eben so Grenzfälle und Extremer gibt,
wo man irgendwie sagen muss, okay,
da fliegt mir irgendwie die Notation um die Ohren,
aber das ist bei ganz vielen Definitionen so,
also dass man auch bei, weiß nicht,
bei Differenzierbarkeit von Funktionen, das ist auch so definiert,
dass einige Funktionen plötzlich nicht differenzierbar sind,
wo man eigentlich das vielleicht ganz gerne hätte oder so,
aber das sind ja alles so Grenzfälle,
also das Wichtigste ist eigentlich abgedeckt
Ja. Genau, so, was haben wir gemacht?
Wir haben das, also was haben wir bisher gemacht,
dieses mit der Laufzeit? Wir haben das bisher nur oberflächlich
gemacht, oberflächlich klingt jetzt so ein bisschen fies.
Also es war bisher so, dass die Algorithmen relativ einfach
sind und dass deswegen eine Laufzeitanalyse auch relativ einfach ist.
Also wenn man sowas wie bei der linearen Suche,
da sieht man irgendwie einen Arry und dann weiß man ja,
okay, eine so eine Vorschleife, dann weiß man halt, was da passiert.
Auch bei dem Insertion Sword ist die Laufzeitanalyse nicht so schwierig für
den Worst Case und für spätere Algorithmen wird das aber komplizierter.
Deswegen werden wir da dann später auch irgendwie ausführlicher sein müssen,
wenn wir irgendwie die Laufzeit begründen.
Und was aber vor allem jetzt auch ins Zentrum rückt,
ist eben diese Korrektheit von Algorithmen,
dass man irgendwie gegeben Algorithmen oder gegeben ein Problem,
ich entwerfe einen Algorithmus,
jetzt muss ich auch zeigen,
dass er das Problem wirklich löst
Genau,
was wir also machen wollen in der Zukunft oft immer so schön im Fettdruck jetzt hier,
wir kriegen ein Problem, jetzt wollen wir einen Algorithmus finden,
der es löst und einen Algorithmus finden,
heißt dann eben auch, jetzt müssen wir auch zeigen,
dass er korrekt ist,
also dass er wirklich das Problem löst und dann müssen wir irgendwie die Laufzeit ermitteln und die Behauptung dann eben auch beweisen.
Das ist so das,
was jetzt in ganz vielen unterschiedlichen Settings kommt und insbesondere für dieses Algorithmus finden,
wollen wir uns auch unterschiedliche Techniken oder Pattern angucken,
die man dann eben bei ganz vielen Problemen einsetzen kann.
Stichwort Greedy Algorithmen, die Vide and Conquer Algorithmen,
dynamisches Programmieren und sowas.
So, und das waren die Fragen,
die man sich jetzt alleine schon von dem,
was wir bisher hatten, so stellen kann,
wie zeigt man denn überhaupt die Korrektheit?
Dann kann man sich überlegen, bisher alle die Algorithmen,
die wir gesehen haben, arbeiten mit Arrays.
Und man kann zumindest die Frage stellen, so hier,
wenn ich das mit irgendwas anderem mache,
geht das dann vielleicht nicht sogar besser.
Also kann ich nicht in Sortieralgorithmus entwickeln,
der mit anderen Datenstrukturen arbeitet und dadurch dann schneller wird.
Können wir überhaupt schneller sortieren als in O von N-Quadrat?
Alles, was wir bisher gesehen haben, war ein O von N-Quadrat.
Wäre jetzt schon sowas wie Merch Sort kennt oder so.
Ja, du geht das irgendwie in O-N-Malogin.
Nächste Frage, kann man das schneller machen,
immer schneller machen
Und dann, was wir jetzt eben in der Wiederholung nicht gesehen haben, aber Laufzeit-Recosive-Algorithmen,
bisher können wir nur die Laufzeit von iterativen Algorithmen besprechen.
Und das, was wir heute machen wollen,
ist erstens und viertens, wir gucken uns jetzt die Korrektheit
eines Algorithmen oder wir gucken uns einen Algorithmus an und zeigen,
dass der korrekt ist.
Und dann kommt der große Themenblock rekursive Algorithmen analysieren.
Fragen noch zur Wiederholung. Die Folie kennt ihr schon.
Fragen zur Wiederholung. Was ist das Zweite?
Okay. Dann Sortierproblem,
kennen wir
Und wie lief dieses Insearch and Sword ab? Ihr könnt ja hier,
da kommt ja so die Idee und rechts steht der Source Code,
dass man immer mal gucken kann, wo sich die Idee irgendwie wiederfindet.
Also dieses Sortieren durch Einfügen, ich starte mit der leeren linken Hand.
Ja, das ist quasi der linke Bereich meines Arrays,
also der Teile bisher zu A 0 geht.
Also naja, bis A minus 1, also der bisher
quasi kein Array-Element enthält. Dann nehmt ihr eine Karte,
jetzt nehmt ihr am Anfang,
nehmt ihr die erste Karte so von,
euer rechter Hand ist voll, die linke Seite ist komplett leer.
Jetzt nehmt ihr die erst dann von der rechten Seite und
fügt sie an der richtigen Position in der linken Hand ein.
Beim ersten ist da nicht viel zu tun,
eine Karte zu sortieren, ist relativ einfach.
So,
jetzt kommt irgendwie die zweite Karte
Und jetzt müsst ihr gucken, jetzt vergleicht ihr
die neue Karte von rechts nach links mit den Karten,
die ihr schon auf der linken Hand habt.
Auf der linken Hand sind die Karten schon sortiert.
Das steht jetzt von mir aus 1, 3,
9. Und jetzt kommt irgendwie die 2. Jetzt vergleicht ihr die 2 Meter 9.
Wenn die neun Größe ist, dann kommt die neun jetzt
also auf das Feld, wo eben die 2 war.
Jetzt steht da 1, 3, 9,
9. Jetzt guckt ihr bei der 3. Stellt ihr fest,
oh, da muss sie jetzt irgendwie, die darf noch weiterrutschen,
da steht da 1, 3, 3, 9.
Und dann merkt ihr, oh, es ist größer als
die 2. Deswegen kommt es jetzt an die Stelle,
die ihr zuletzt freigemacht habt.
Also an die Stelle von der 1, 3,
dann steht da 1, 2, 3,
9. Das ist das,
was da bei dem Algorithmus in der Wire-Schleife passiert
Und das Wichtige, was wir auch gleich beim Beweis ausnutzen wollen,
zu jedem Zeitpunkt sind die Karten auf der linken Hand sortiert und
die Karten auf der linken Hans sind jeweils die obersten Karten des Haufens,
also quasi die Karten,
die im Arry den linken Bereich ausmachen.
Algorithmus, ich hoffe, da steht jetzt das Gleiche.
Zwei bis innen, KIJ, I, gleich outminus 1,
weil die USA 0, da, da, da.
Ja, genau,
sieht gut aus
Hier, ich fange, also mit J gleich eins,
damit beschäftige ich mich gar nicht, weil das erste Element
quasi sortiert ist, da brauche ich nichts machen.
Jetzt fasse ich das erste Element an für J2, sage,
okay, A2 ist jetzt mein Schlüssel, den will ich jetzt einsortieren.
Und dann fange ich bei dem ersten Element,
was jetzt daneben steht, das ist quasi mein,
am rechtesten weitstehendes Element auf der linken Hand.
Da gucke ich jetzt, ist es kleiner oder größer,
wenn es da schon,
wenn da der Schlüssel schon größer ist,
dann muss es an die Stelle quasi
Ja, und dann gehe ich halt hier in dieser Wahlschleife durch,
solange das I noch irgendwie einen Wert größer als Null hat.
Kurze Bemerkung hier. Unsere Array starten hier bei dem Pseudocode
ständig von eins. Bei Java und so starten wir immer
bei Null bei und starten immer von eins. So,
das heißt, solange das I größer ist als Null,
kann ich mit AI noch irgendwie auf so ein Array-Element zugreifen.
Und dann gucke ich immer, ist AI größer als der Schlüssel.
Wenn das nicht mehr größer als der Schlüssel ist,
dann habe ich die Stelle gefunden,
wo ich
meinen Schlüssel hinpacken muss
Größer ist als der Schlüssel,
dann kann ich dieses Element nehmen und ist ein Platz weiter nach rechts schieben,
weil ich suche ja die Stelle für mein Key-Element und dann rücken
die anderen immer einen weiter nach rechts und ich verminde halt diesen In-I-C. Ja,
und irgendwann wird entweder die Bedingung hier erfüllt,
das AI größer ist als der Schlüssel oder I wird null und dann höre ich halt auf.
Genau,
und wenn ich aufhöre,
dann kommt eben an diese Stelle der Schlüssel und dann dieses AI plus 1,
das hängt mit diesem I gleich I-Minus ein zusammen,
dass ich da ständig immer noch verringere und irgendwann breche ich
ab und dann muss ich halt an die Stelle
das schreiben
Also wenn ich an der Stelle A0 erst abbreche sozusagen,
also wenn ich immer merke, alle Elemente sind noch größer als mein Schlüssel und mein Schlüssel muss ganz nach links,
dann bricht die halt ab bei I gleich null. Naja,
und dann soll das Element nicht an die Stelle A0,
weil da gibt es ja gar nichts,
sondern das soll an die Stelle A1. So,
jetzt ist das ja trotzdem so, ich weiß nicht,
wie euch das geht, aber wenn ich da so drauf gucke,
dann denke ich so, ja, Idee habe ich verstanden,
also quasi die Folie davor.
Ich kann mir auch vorstellen, dass das so ungefähr die Idee abbildet,
aber dieser ganze komische Indie-C-Gespiele-Kram da, also so hundertprozentig sicher,
dass das gerade funktioniert, wäre ich mir jetzt nicht unbedingt.
Ja, dass man irgendwie Da verringert man,
da guckt man sich das AI plus, da nimmt man nie minus eins,
man guckt irgendwie das AI-Element an, steht das dann weiter.
Also ich weiß nicht mehr, ich weiß nicht, wie euch das geht.
Ich finde das so ein bisschen, dass du in die Zähschubserei,
das will man lieber beweisen, dass das richtig ist.
Unseren Beweis, in dem Fall hier, so zwei Schleifen,
kann man mit Schleifen in Varianten arbeiten.
Muss man nicht, kann man aber. Steifen in Varianten sollte irgendwas sein,
was so was Vor- und Nach-Iteration einer Schleihe,
also quasi was jedes Mal, wenn ich einen Schleifenrum neu ausführen will,
was dann immer gilt, eine Schleifenden-Variante.
Das ist quasi invariant gegenüber einer Ausführung der Schleife. So,
jetzt kann man sich überlegen hier irgendwie,
fällt einem irgendwie eine Schleifenden-Variante ein und wir hatten ja vorher schon hier gesagt,
zu jedem Zeitpunkt sind diese Karten auf der linken Hand sortiert.
Jetzt kann man sich überlegen, dass jedes Mal,
wenn ich hier in diesen Vorschleifenrum freiengehe, kann ich sagen,
die Elemente von A1 bis irgendwie AJ sollen schon sortiert sein oder sind schon sortiert.
Das kann ich als Schleifenden-Variante nachher benutzen. Die wissen mal,
wenn ich da reingehe, weiß ich, der Teil ist
schon irgendwie sortiert und da sind auch genau die Elemente,
die da vorher waren
Wenn ich die ersten vier Elemente sortiert habe,
waren das auch vorher die ersten vier Elemente neben Erry.
Ich nehme ja nicht plötzlich so wie bei diesem Max-Sort
irgendeinen Swap-Kram oder sowas. Das kann man versuchen auszunutzen,
weil man dann beim letzten Durchlauf sagen kann,
ah ja, jetzt muss also das Element von A1
bis AN sortiert sein und genau die Elemente enthalten,
die da vorher auch drin waren.
Also das, da wollen wir machen. Wir wollen sagen,
zu Beginn jeder Iteration der Vorschleife besteht das Teilfeld A1
bis J minus eins aus den ursprünglichen,
dort auch befindlichen Elementen und in geordneter Reihenfolge.
Was man jetzt noch machen muss,
man muss sich hier nochmal drüber unterhalten, zu Beginn jeder Iteration
Zu Beginn heißt Nachzuweisung des neuen Wertes ein J und vor
dem Test im Schleifenkopf.
Also man hat ja...
Das hier
Denn die Vorschleife kann ich ja zu sowas aufdröseln.
Normalerweise passiert ja dann sowas, wenn man das jetzt kompiliert,
J wird am Anfang die Zahl 2 zugewiesen und dann wird
bei jedem Schleifen umgeguckt, gilt die Bedingung.
Dann läuft der Schleifen Rumpf durch und ganz am Ende erhöhe ich das.
Und dann gucke ich wieder, gilt die Bedingung und erhöhe das
wieder am Ende. Also am Anfang gucke ich immer,
gilt die Bedingung am Ende, erhöhe ich das immer.
Deswegen halt Nachzuweisung des neuen Wertes. Das macht Sinn,
das kommt quasi noch am Ende.
Und vor dem Test im Schleifenkopf, also bevor ich gucke,
ob J immer noch diesen Wert kleiner gleich endet
Ja, und jetzt beweise ich, dass diese schleifenden Variante immer gilt.
Und dann kann ich nachher Schluss folgern, die hört ja erst auf,
wenn J diesen Wert N plus 1 hat.
Wenn sie dann aufhört, dann weiß ich,
die Schleifenvariante gilt ja wieder. Und dann bedeutet das,
das Teilfeld von 1 bis N plus 1, minus 1,
also bis N, besteht gerade aus den Elementen,
die da vorher aufwanden und es sortiert.
Was ich also machen muss, ist,
ich muss zeigen, dass die schleifenden Variante immer gilt.
Das geht jetzt genauso wie so ein Induktionsbeweis.
Ich zeige, dass das am Anfang gilt, Initialisierung,
die in Variante gilt vor der ersten Ausführung
Fortsetzung, das ist so ähnlich wie so ein Schritt von
Ende auf N plus 1 bei der Induktion,
wenn die in Variante vor der Iteration irgendeiner Schleife war ist,
dann ist sie auch danach wahr, also beziehungsweise vor der nächsten Iteration.
Und Terminierung, die Schleife bricht irgendwann ab. Und
wenn ich das alles gezeigt habe, dann weiß ich,
diese schleifenden Variante ist wirklich eine Schleifenden-Variante, gilt immer.
Und dann ist es hoffentlich so, dass ich mit der
schleifenden Variante irgendwas machen kann.
Ich kann mir ja auch als schleifenden Variante nehmen,
J ist immer kleiner gleich N plus 1. Gilt auch bei jedem Durchlauf?
Hilft mir aber irgendwie nicht. Also es sollte schon
irgendwas sein,
womit ich arbeiten kann
Und in dem Fall kann man das ja ziemlich gut dann.
Ja, Initialisierung, rechts könnt ihr euch immer den Code angucken.
Vor der allerersten Iteration ist J gleich 2,
das ist ja quasi das, was ganz am Anfang passiert.
J wird zugewiesen, Initialisierung vor der ersten Iteration ist J
gleich 2. Bevor ich überhaupt in so eine Iteration reingehe,
weiß ich J den Wert 2 zu.
Dann besteht dieses Teilfeld von A1 bis J minus 1,
J ist 2, dann ist das also nur das Teilfeld,
das aus dem allerersten Element besteht.
Naja, das war auch ursprünglich da und ein Element ist
immer sortiert, also gilt die Initialisierung.
Da ist nicht so viel
zu tun
Schwierigerer Teil Fortsetzung, zu zeigen, ich muss jetzt zeigen,
dass ich bei jeder Iteration, dass das immer gilt.
So, und jetzt muss man gucken, was passiert da.
Es wird die richtige Position für dieses Element AJ gesucht.
Also ich setzte den Schlüssel auf AJ,
sucht dann die richtige Position in diesem Bereich 1
bis J minus 1. Und da packe ich es hin.
Das führt dazu, das sieht man sofort,
dass man sagen kann, okay,
es sind auch nachfolgend nur die Elemente von 1 bis J
in diesem Arry
Weil die von 1 bis J minus 1,
die schiebe ich ja nicht plötzlich woanders hin,
sondern im schlimmsten Fall kommt alles eins weiter nach rechts,
also weibe ich in diesem Bereich 1 bis J.
Und was dann nochmal schwieriger zu zeigen wäre, wäre,
dass man auch die richtige Position findet und da dieses Element AJ hinsetzt.
Das ist also sortiert bleibt. Das kann man,
wenn man möchte,
nochmal mit einer schleifenden Variante für die Wahlschleife zeigen,
dass man sagt, okay,
jetzt mache ich mir noch eine schleifende Variante für die Zeilen
4 bis 7 da und zeigt dann dadurch,
dass eben dieses Element an die richtige Stelle kommt.
Und zuletzt Terminierung, naja, Weißschleife muss terminieren, weil wie gesagt,
dass ihr ja auf jeden Fall immer um eins reduziert wird.
Und entweder breche ich dann eben ab,
wenn ihr den Wert null erreicht, oder es tritt eben
irgendwann dieser Fall auf, AI ist größer als der Schlüssel.
Breche es auf jeden Fall ab. Vorschleife terminiert auch,
wenn die Weißschleife immer terminiert, vier bis sieben,
jetzt kann man das geistig einmal zuklappen und sich angucken,
was noch übrig bleibt.
2, 3, 8, nirgendwo wird das J irgendwie erhöht,
in den Zeilen 4 bis sieben auch nicht.
Das heißt, nirgendwo wird es verringert, das heißt,
jedes Mal wird es,
wenn ich wieder in die Iteration reingehe, um eins erhöht.
Naja, und dann muss es
irgendwann abbrechen
Irgendwann erreiche ich dann dieses N. Also,
dass die beiden terminieren, ist ziemlich einfach zu sehen.
Der schwierige Teil wäre noch hier eben, sich davon zu überzeugen,
dass die richtige Stelle gefunden wird in der Weichleife.
Ja, genau. Ja, und wenn sie jetzt abbricht,
dann die Vorschleife kann nur abbrechen,
wenn das J den Wert N plus 1 annimmt,
sonst bricht das nicht ab.
Da gibt es ja auch nirgendwo seine Anweisungen,
wo man rausspringen würde
Und wenn das J den Wert N plus 1 einnimmt,
dann setzt man das in die Innenvariante ein und dann erhält
man gerade die Aussage, die man haben will.
Das ist nämlich die A1 bis AN aus den ursprünglichen Elementen
besteht und in sortierter Reihenfolge ist.
Das ist ja genau das, was man haben will.
Ich habe keine Elemente dazugekriegt, Reihenfolge ist sortiert, fertig.
Laufzeit fehlt noch, die sieht man auch relativ schnell,
der rumpft der Vorschleife, wird N minus eins mal ausgeführt.
J ist zwei, drei, vier, fünf,
sechs bis hin zu Ende, also wird das N minus eins mal ausgeführt.
Dann kann man sich überlegen, wie oft wird im
schlimmsten Fall die Wildschleife ausgeführt
Ja, J minus 1 mal. Also wenn J den Wert 2 hat,
dann kann ich die Weißschleifen maximal einmal ausführen,
wenn ihr auch den Wert 3 habt,
kann ich sie maximal zweimal ausführen und so weiter.
Und dann bin ich dabei 1, 2 plus dödödö bis plus end
minus 1. Und dann wird es so oft maximal ausgeführt,
so viele Schritte habe ich dann irgendwie und das ist in O von Endquadrat.
Und wenn ihr das hier nochmal genau sehen wollt,
wenn ihr hier,
ob das wirklich gefunden wird und nochmal mit der Waldschleife da ein bisschen argumentiert,
dann kann man das im Kormen in dem Kapitel 2
-2
nochmal finden
Aber das wäre ein Beispiel für einen Korrektheitsbeweis für einen noch
relativ übersichtlichen Algorithmus. In dem Fall mit schleifenden Varianten.
Gibt auch noch andere Techniken, aber steifenden Varianten,
gerade bei Schleifen, bieten die sich irgendwie an.
Fragen. Wer fand das schwierig? Falsche Frage.
Das dritte ist total fies, ich glaub dir das.
Ich glaube auch, dass noch viel mehr Leute das
schwierig fanden und die melden sich alle nicht.
Er fand das total einfach.
Auch niemand
Wer hat es nicht verstanden und ist sich deswegen nicht sicher,
wie er die Schwierigkeit einzuschätzen hat? Das Wichtige,
also das Schwierige ist eigentlich auf eine sinnvolle Schleifen-Variante zu kommen und
über allen Beweisen ist das im Grunde genommen so ein Wechselspiel.
Hier sieht das jetzt immer so aus, als ob man
kommt halt auf die schleifenden Variante und dann beweist man, dass die gilt.
Das ist natürlich Schwachsinn, so führt keiner einen Beweis.
Man hat irgendwie eine Idee,
was wohl die Schleifen in Variante sein könnte,
fängt damit an zu arbeiten,
stellt beim Beweis irgendwo fest an irgendeiner Stelle,
hakt es und dann passt man
die schleifende Variante an
Oder verwirft sie komplett und versucht, sich eine neue auszudenken.
So führt man eigentlich Beweise. Dass mathematische Arbeiten,
wie das immer irgendwie in Vorlesungen passiert, so irgendwie Definitionssatz,
Beweis, Definitionssatz, Beweis, so arbeitet kein Mathematiker.
Also es ist ja nicht so,
dass man sich hinsetzt und irgendwie denkt so, hm,
ich beweise mal, dass für Graphen mit Endknoten,
wenn Cardin wird, dreimal N minus acht hat,
folgendes gilt.
Das macht ja keiner. Warum nicht? Ja,
man redet. Man redet aber gut. Und danach beweist
man, dass das gilt. Wie rate ich gut?
Ja, schöne Frage mit Erfahrung
Das Interview ist jetzt einfach so. Ja,
es ist quasi eine, die Frage war gerade,
ob die Innenvariante eine Bedingung ist, die immer gilt.
Ja, wobei du beweist, dass sie immer gilt.
Also du überlegst dir irgendwie eine Schleifenden-Variante,
die steckt natürlich auch irgendwie so ein bisschen bei deiner Konstruktion,
bei deiner Konstruktion des Algorithmus ist schon drin.
Du konstruierst irgendwie einen Algorithmus, hast ja eine bestimmte Idee,
also bei diesem Insertion-Sort hatte man ja irgendwie die Idee,
den ganzen Teil rechts vom Array sich überhaupt nicht anzugucken,
sondern immer nur mit dem vorderen Teil irgendwie zu arbeiten.
So und dann wusste man auch immer,
ja, der muss ja sortiert sein,
weil das neue Element will ich an genau die richtige Stelle
setzen und so
Also da schwingt er schon so bei der Idee schon
mit drin, was man vielleicht als Schleifenvariante nutzen könnte.
Und dann stellt man die halt irgendwie auf. Und wenn man
sie dann bewiesen hat, dann weiß man, die gilt immer.
Wobei immer, die Bedeutung immer ist hier zum Beginn der Iteration,
also an der beliebigen Stelle, im Kodelt sie ja nicht immer.
Weil wenn ich da irgendwie gerade rum hühne,
dann muss das jetzt nicht unbedingt gelten gerade.
Aber einfachstes Beispiel, zwischendurch ist der Schlüssel gar nicht.
Also das Element, was ich gerade reinsortieren will,
das ist zwischendurch gar nicht mehr in dem Array drin,
dann gilt die schleifenden Variante nicht.
Also wenn ich irgendwie hier den Key auf AJ setze und dann einmal
in dem in dem Waldschleifenrumpf AI plus 1 gleich AI machen ganz am Anfang,
dann ist mein Element, was jetzt der Schlüssel ist,
gar nicht mehr in dem Arry drin.
Dann würde die schleifenden Variante gerade nicht gelten. Genau,
aber halt zu Beginn der Iteration gilt sie dann immer.
Und damit kannst du dann arbeiten. Für mich ist zwar die,
der lebt die ganze Zeit als Plusgebiet, welcher bewertet,
so blöd er ja auch nicht mehr das Ganze,
weil der Mann ein Schuld war, formalisiert,
für sich gesehen.
Der Brauch ist voll setzen und die Definitionen, das ist so.
An dem wir versteht man gar nichts mehr auf Holt Kritik,
das war in der Zentrale
Nö. Also die Beweise und Sätze,
die sollen das ja eigentlich eher unterstützen, das verstehen.
Also wenn du sagst, die Sätze und Beweise verwirren mich,
aber die Idee ist doch klar, dann passt da schon irgendwas nicht zusammen.
Also dann ist das eher so eine Begründung,
dass man sagt, wieso ist auch offensichtlich, dass es gilt.
Und wenn dann aber in vier Seiten Beweis kommt,
dann kann es nicht so offensichtlich gewesen sein.
Also die Idee lässt sich zwar manchmal leicht transportieren, aber ich meine,
es ist ja auch nicht damit getan, dass ich sage,
ja, ja, das funktioniert so wie beim Kartenspiel.
Die rechte Hand wird immer einsortiert. Das ist zwar irgendwie
die Idee, die ich leicht transportieren kann,
aber es ist ja
kein Algorithmus
Und das Richtige, der richtige Algorithmus dann, da soll,
also das soll eigentlich eher das Verständnis unterstützen davon,
dass der Algorithmus korrekt ist und es nicht verwirren.
Sondern ja gerade davon überzeugen, Beweis soll ja immer
die Leser davon überzeugen, dass es klappt.
Ich wollte ja meinen Screensafer umstellen,
dass da immer so ein Text kommt,
nicht so viel reden,
Frank,
nicht so viel reden,
Fragen. Fragen, Fragen, Fragen, Fragen.
Okay, dann das nochmal hier zum Vorgehen bei Korrektheitsbeweisen.
Erstmal gleich der erste Punkt so, die fiese Einschränkung ist
kein generelles Verfahren. Also ein Algorithmus als korrekt zu beweisen,
da schminkt es ja schon mit, das ist ein Beweis.
Das heißt, sie müssen also jeden Algorithmus irgendwie neu machen,
was man euch halt an die Hand geben kann,
sind irgendwie Techniken, Ideen, wie man sowas machen kann.
Aber das heißt halt nicht, dass man das wie so
ein Rezept jetzt anwenden kann.
Der Algorithmus selbst ist ein Rezept, aber der Korrektheitsbeweis
eben nicht
Schleifen in Varianten, insbesondere sind halt viel,
sind nützlich so, aber kann man halt nicht automatisch bestimmen.
Das hängt auch zusammen mit der Unentscheidbarkeit vom Halteproblem
und damit auch mit der Unentscheidbarkeit von diesen Programmiersprachengeschichten.
Wenn ich schleifende Varianten nämlich automatisch bestimmen könnte,
dann könnte ich automatisch Korrektheitsbeweise führen,
wenn ich automatisch Korrektheitsbeweise führen kann, kann ich das Halteproblem entscheiden.
Funktioniert nicht. Steht ja auch irgendwo, ja,
hier. Wie bei mathematischen Beweisen. Und bei der Beweisführung
ist irgendwo so ein kreativer Schritt nötig.
Und der lässt sich eben nicht automatisieren oder zumindest nach
aktuellem Kenntnisstand
Erfahrung hilft, und das ist genau das,
was wir in der Vorlesung machen wollen,
dass wir irgendwie uns mehrere Beispiele angucken, gucken, wie beweist man das,
irgendwie in den Übungen, selbst mal einen Beweis führen.
Darum wird es gehen. Und da noch eine Anmerkung,
ist auch problematisch, relativ häufig wird die Idee des Algorithmuses als korrekt bewiesen.
Und in der Implementierung können dann wieder andere Sachen, Fehler und so auftreten.
Selbst wenn ihr jetzt den Pseudocode als korrekt nachgewiesen habt,
also selbst wenn man jetzt sagen würde, oh,
das passt irgendwie, und jetzt implementiere ich das in irgendeiner Programmiersprache,
Bei dem Beispiel ist das Mapping relativ,
klar, von dem Pseudoko zur Programmiersprache.
Bei anderen Sachen ist das nicht immer ganz so klar.
Also da ist dann quasi im Pseudokode eine Zeile und in
der Programmiersprache ist es deutlich umfangreicher.
Und da können dann wieder Probleme auftreten. Streng genommen müsste man
einmal die Idee oder dem Pseudokode als korrekt nachweisen und danach
dann eben die eigentliche Implementierung auch nochmal anfassen und auch als korrekt nachweisen.
Dafür gibt es dann so Tools,
da kann man dann so mit Horsemantel, axomatischer Semantik,
Horkalkül und so rangehen.
Das geht über die Vorlesung hinaus,
aber das ist dann so im Masterstudium FG3-Stoff und sowas,
wie man das auch noch attackieren kann
Das nur, damit ihr wisst irgendwie,
ihr habt irgendwie ein Problem, ihr wollt einen Algorithmus implementieren.
Jetzt überlegt ihr euch erstmal, dass eure eigentliche Idee
das Problem löst und danach müsstet ihr eigentlich nochmal gucken,
passt das jetzt auch zu meiner Implementierung.
Also deckt mal eine Implementierung wirklich die Idee ab und so,
ist das immer noch richtig.
Dass wir dann auch nochmal nächster Schritt.
Genau, das war es zu dieser Korrektheit von Algorithmen.
Und jetzt kommt dieses recht fiese Thema mit den rekursiven Algorithmen.
Das hatte ich ja letztes Mal schon,
dass man irgendwie gesagt hat, so hier,
Fakultätsfunktion kann man rekursiv bestimmen und bei diesen rekursiven Algorithmen
helfen halt unsere bisherigen Technik nicht so gut
In dem Beispiel würde man vielleicht noch sagen, naja,
das ist relativ klar,
dass ich hier irgendwie in dem Algorithmus irgendwie einmal teste und dann springe ich wahrscheinlich da rein und auch da teste ich einmal,
also da kann man auch schon irgendwie annehmen,
dass das irgendwie ein Ofen Ende ist,
aber wenn ihr euch kompliziertere, rekursive Algorithmen vorstellt,
ist es eben nicht mehr so richtig klar,
wie man die analysiert.
Also wenn ich irgendwie ein großes Array habe und jetzt rufe
ich die gleiche Funktion einmal mit der ersten Hälfte des Arrays
auf und dann nochmal mit dem letzten Viertel oder so und dann gehe ich da rein und danach füge ich das irgendwie zusammen und so,
dann ist nicht ganz klar,
wie die Laufzeit ist,
weil ich da ja auch irgendwie in dem Stack
quasi bei dem Methodenaufruf immer hin und her springe
Ja, kann man aber auch machen. Und zwar,
oh, habe ich zwei Folien vergessen. Kann man auch
machen. Kommen wir gleich zu. Erstmal der Einschub,
die lassen sich alle rekosiven Algorithmen, lassen sich halt iterative Algorithmen schreiben.
Und auch andersrum. Aber, ja, hier. Aber
manchmal ist das eben einfacher, einen rekursiven Algorithmus zu schreiben,
weil das dem Problem angemessener ist,
als eine iterative Variante zu schreiben.
Und man sieht dann quasi eher am Kot,
dass der korrekt arbeitet.
Deswegen sind rekursive
meistens nett so
Und dann muss man halt, kann man so ein bisschen abwägen,
wenn ich iterativ schreibe, dann umgehe ich diesen ganzen Kram,
der beim rekursiven Aufruf drin ist,
dass ich irgendwie Funktionsparameter auf dem Stack tue und all solche Sachen,
also diesen ganzen Overhead, den ich durch den Methodenaufruf habe,
den spare ich mir, wenn ich das iterativ implementiere.
Es kann aber passieren, dass ich,
wenn ich jetzt das iterativ implementiere,
ich eigentlich gar nichts anderes mache, als das alles nachzubauen,
was ich normalerweise von der Programmiersprache geschenkt kriege,
dann lohnt sich das nicht so richtig, das iterativ zu schreiben.
Also so muss man so ein bisschen abwägen, wenn man
iterativ oder rekursiv schreiben. Es gibt auf jeden Fall Settings,
bei denen es sehr schön ist, was Rekursives zu schreiben.
Und deswegen lohnt sich das eben, sich anzugucken,
wie man die Laufzeit von diesen rekursiven Algorithmen bestimmt.
Und dafür brauchen wir dieses Thema Rekurrenz oder auch Rekursionsgleichung.
Hattet ihr das eine Matte in DM
oder so
Also Mathe 1, nee. Ganz typisches Beispiel. Türme
von Hanoi. Ich habe so drei Stangen, A,
B, C und auf einer Stange sind so mehrere Plättchen.
Ganz unten ist die größte Scheibe und dann geht das immer
so weiter hoch bis zur kleinsten Scheibe.
Dann hat man so ein Türmchen aus Scheiben und dann ist
das Ziel halt das Türmchen von der Stange A auf die Stange C zu kriegen.
Und dabei darf ich halt nicht völlig beliebig nehmen,
sondern die Scheiben dürfen immer nur größere, kleinere dürfen nur auf größeren Scheiben liegen.
Also muss ich zuerst irgendwie sowas machen wie die oberste Scheibe,
die am kleinsten ist, die tue ich auf die mittlere Stange,
dann nehme ich irgendwie die zweite,
tue sie auf die erste,
tue das da wieder hin und so
und dann muss das irgendwie
Muss ich das lösen? Ein rekursiver Algorithmus, um das zu machen,
das iterativ zu beschreiben, das wird schon anstrengend.
Da muss man irgendwie beschreiben, wie man an die Unterste
rankommt und so. Das ist irgendwie doof. Rekursiv lässt
sich das total einfach beschreiben. Da sagt man,
ich verschiebe die endminus eins oberen Scheiben von A nach B.
Dann stehen also mein Türmchen mit den N-Minus-Einscheiben, ist jetzt auf B.
Dann nehme ich die größte, die ja jetzt frei ist,
von A2D auf C. Und dann nehme ich die N-Minus-Einscheiben,
die gerade auf B waren und tue die auf C. Dann bin ich fertig.
Habe ich das Problem rekursiv gelöst. Jetzt muss ich natürlich
irgendwie gucken, wie löse ich denn,
dass die N-Minus-1 oberen Scheiben von A nach B
zu kriegen und sowas
Aber da steckt halt in der Rekursion mit drin,
das kriege ich dann quasi irgendwie geschenkt.
Ist korrekt. Funktioniert auch. Frage ist Laufzeit.
Jetzt versucht man die Laufzeit irgendwie in Abhängigkeit von der Tee
von N. N ist irgendwie die Anzahl der Scheiben.
Ich interessiere mich für die Zeit, ich interessiere mich für T von N.
Jetzt will ich irgendwie eine Gleichung für T von N aufstellen.
Die kann, oder die sieht so aus.
T von N soll die Anzahl der Verschiebung sein,
die ich brauche
Und wenn ich nur eine Scheibe habe,
dann ist es einfach, dass der Rekursionsabbruch,
dann muss ich null Scheiben, N-minus 1,
N-minus 1, N-minus 1 ist null,
dann muss ich null Scheiben von A nach B verschieben,
dann verschiebe ich die Größe von A nach C und danach verschiebe ich eine,
nee, gar nichts mehr, von wegen der erzähle.
Also brauche ich nur eine Verschiebung, das ist einfach.
Und für den anderen Fall sage ich,
ich habe ja zweimal diesen rekursiven Aufruf mit N-minus 1.
Einmal am Anfang und einmal am Ende. Das ist zweimal
T von N-minus 1. Und dann kommt dieser eine Schritt dazu,
wo ich die größte Scheibe von A nach C lege
Das ist zwar schön, jetzt kann ich losgehen und sagen,
das ist die Laufzeit von dem Algorithmus.
Korrektheit kann man auch zeigen, das wollen wir uns mal
in dem Fall sparen. Aber das ist keine geschlossene Form
. Ich finde eine geschlossene Form viel schöner.
Also ich will irgendwie sowas haben wie Tee von Ende,
ist gleich fünfmal N, damit ich weiß,
wenn ich zehn Scheiben habe, brauche ich 50 Schritte oder so.
Sowas will ich haben. Ideen, wie ich das mache,
wie ich da rangehen könnte. Ich könnte raten. Man
verglänzt nicht jedes Mal, man kann es gleich aussagen, Mhm.
Man rechnet sich ein paar Werte aus und guckt,
ob ein Muster da ist. Machen wir das mal.
Wir berechnen das für kleine Werte und dann raten wir doch,
was er meinte, wir gucken, ob ein Muster da ist,
dann raten wir mal und dann gucken wir,
ob wir das, was wir geraten haben, beweisen können.
Amen. So aussieht, den Wert für N gleich 1
zu bestimmen, ist einfach, das ist eins.
Wenn ich als nächstes den Wert für 2 bestimmen will,
dann nehme ich mir zweimal den Wert von 1,
also von Tee von 1 oder die 1 dazu,
der Wert von Tee von 1 war 1,
also zweimal 1 plus 1,
dann kommt 3 raus und immer so weiter
Also Tee von 1, da kriege ich den Bett 1 raus.
Tee von 2 ist zweimal der Wert von Tee von 1,
plus 1, also 3. Tee von 3 ist zweimal der Wert von Tee von 2,
also die 3 plus 1, von 7 raus.
Tee von 4 ist zweimal der Wert von Tee von 3,
also die 7 plus 1, kommt 15 raus und immer so weiter.
Sieht man, ne? Was ist das? Genau,
2 Euro in minus 1. Naja,
zumindest für die Werte von Engleich 1 bis 10.
Ob das jetzt auch noch bei 100 der Fall ist?
Hm, bei 200 oder so, ne?
Und so lange will man die Tabelle nicht aufschreiben,
also muss man
es noch beweisen
Beweisschema. Ja, ja, das ist der Formel.
Genau. Vollständige Induktion. Zeigen, dass das für einen
gleich eins gilt. Dann nehmen wir an,
dass es für Enden gilt und zeigen,
dass es für N plus eins gilt.
Und wir benutzen, genau, was du gesagt hast,
wir benutzen die Formel hier an irgendeiner Stelle.
Also sinnvollerweise beim Induktionsschritt. Also beim Induktionsanfang benutzen wir
den oberen Teil hier sehr wahrscheinlich.
Und beim Induktionsschritt benutzen wir den unteren da.
Dann müsste das eigentlich funktionieren
Gucken wir mal, das ist die, die gegeben ist und wir wollen zeigen,
dass T von N gleich 2 hoch N minus 1 ist.
Induktion, Induktionsanfang, NS1. Naja, Dennis,
T von 1, nach der Formel hier,
ist T von 1.1. Und nach der Formel hier ist T von 1.1,
2 hoch 1, minus 1, also 2 minus 1,
also auch 1, also passt das.
Das ist okay, Induktionsanfang erledigt. Induktionsannahme,
wir nehmen an, dass für irgend so ein N größer
gleich 1 die Behauptung gilt.
Also T von N gleich 2 hoch
N minus 1 ist
Und zumindest Fang gleich eins haben wir das ja gerade gezeigt und wenn wir jetzt gleich zeigen,
dass es dann für N plus eins gilt,
würde es mir ausgilt für zwei, drei, vier,
fünf, sechs und so weiter.
Also für alle. Induktionsschritt, T von N plus eins. So,
jetzt dürfen wir die Induktionsannahme noch nicht benutzen,
weil die sagt uns ja nur,
was über T von N. Wir müssen also irgendwie so umformen,
dass wir was mit T von Ende stehen haben.
Naja, T von N plus eins,
jetzt können wir einmal den unteren Teil hier der Gleichung benutzen.
Dann ist T von N plus eins das Gleiche wie zweimal
T von N plus 1, minus eins,
also T von N. plus eins.
Also zweimal T von N plus eins. Und für das
T von N, da dürfen wir jetzt die Induktionsannahme benutzen.
Und die hat uns gesagt, T von Dennis 2
hoch N minus Eis
Einsetzen, Telefon nennen, zwei auch in minus eins einsetzen und ausrechnen.
Zweimal zwei Hochendes, zwei hochend plus eins. Zweimal minus eins
ist minus zwei, eins dazu addiert ist minus eins.
Dann habe ich also T von N plus eins,
ist zwei Hochend plus eins, minus eins,
also genau die Formel, die wir zeigen wollen,
wenn wir überall, wo N steht,
N plus eins einsetzen.
Also sind wir fertig. Das war die erste Methode
Die war, in dem Beispiel ist das noch relativ straightforward so,
ein paar Werte einsetzen. Die Gleichung ist auch relativ gut abzulesen.
Man kann sich schon irgendwie vorstellen, dass wenn da nicht sowas rauskommt,
sondern wenn da sowas rauskommt wie drei Hochend, minus fünf,
das sieht man vielleicht nicht mehr so offensichtlich. Also die Zweierpotenzen,
die sind uns als Informatiker jetzt irgendwie relativ vertraut,
da hat man das schnell gesehen,
wenn das jetzt irgendwie was anderes ist oder wenn das sowas ist wie drei Hochend,
minus Endquadrat plus fünf N oder so,
das kann man auch nicht mehr so richtig gut ablesen.
Also ich zumindest nicht. Andere Methode, wie man
das machen kann, was fällt euch noch ein?
Was könnte man vielleicht, was könnte man
noch machen
Hat auch was damit zu tun, irgendwie zu hoffen,
dass man irgendwann ein Muster erkennt.
Was? Ja, ja, ja, ja,
ja. Also das führt, glaube ich,
ein bisschen zu weit
Also zumindest kürzlich mit der Ahnung, mit der Kultursportart,
nicht allgemein. Nein, allgemeine Formel, nein.
Was kann man machen, ohne zu googeln? Das könntet
ihr mal ausprobieren. Tippt mal in Google Tee von N
gleich zweimal Tee von N minus eins plus eins ein.
Ich würde mich mal, ja mach mal,
ich würde mal interessieren, was rauskommt.
Switch, der Rekordklon und der Google zwei neue Bäume auch.
Das heißt, ich kann der ja vor jedes Bild war.
Ja, sowas kann man auch machen. Die Idee war gerade, ich kürze mal kurz ab. Die Idee war gerade,
dass man ja quasi so einen Baum aufmalt,
dass man irgendwie sagt,
T von N und dann habe ich zweimal die,
also dann mache ich mir so zwei Zweige mit T von N
minus eins und am Rand merke ich mir vielleicht noch plus eins oder so und dann mache ich das immer so weiter,
dass ich irgendwie mir Bäume angucke und damit versuche zu arbeiten.
Das könnte man auch machen. Ich glaube,
das macht man üblicherweise, wenn man eher beweisen will,
dass die Verfahren, die wir machen, korrekt sind oder so.
Also wir machen nachher noch das Mastertheorien,
wenn man das als korrekt beweisen will, dann macht man genau solche Ideen,
dass man irgendwie so mich Bäumen skizzen macht.
Hier geht es einfacher, einfacher.
Man kann das hier
Tee von N gleich zweimal TVM minus 1. Man kann das
ja allgemein abwickeln. Das, was wir vorhin gemacht haben,
als er gesagt hat, wir bestimmen ein paar Werte.
Da haben wir quasi die Werte immer eingesetzt.
Das war auch so wie abwickelnd, dass man gesagt hat,
Tee von 8 ist zweimal Tee von 7 plus 1,
ist also zweimal, zweimal Tee von 6 plus 1 plus 1 oder so.
Und das macht man jetzt allgemein. Das heißt,
man arbeitet mit T von N und guckt mal,
was passiert, wenn ich einmal abwickel, zweimal abwickel,
dreimal abwickel, viermal abwickel.
Und dann guckt man, ob man ein Muster erkennt,
wie die Formel aussieht, wenn man K mal abgewickelt hat
Bei dem Beispiel hier geht es jetzt mit dieser ersten Methode
schneller. Bei späteren Beispielen, die wir sehen werden,
wenn man sowas hat wie TVN gleich dreimal Tee von N,
Viertel oder sowas.
Da funktioniert es nicht mehr so gut mit der ersten Methode.
Da braucht man dann diese zweite. Und damit,
weil man die hier schön sehen kann,
wollen wir die einmal an dem Beispiel einüben.
Also zweite Methode, sogenannte Abwicklungsmethode oder Substitutionsmethode.
Ich fange einfach an und sage, TVN ist ja zweimal
TVN minus 1 plus 1. Das ist einfach die Gleichung.
Und jetzt gehe ich in diese Gleichung
rein hier oben
Ich interessiere mich jetzt für T von N-minus 1. Das heißt,
ich gucke jetzt hier, was ist T von N-minus 1,
T von N-minus 1 ist das Gleiche wie zweimal,
T von N-minus 1, minus 1, also N-minus 2,
plus 1. Das heißt, ich mache das dann.
Und jetzt rechne ich das einmal aus oder vereinfache das.
Die habe ich dann irgendwie zweimal, zweimal T von N-minus 2,
also viermal T von N-minus 2 plus 2 plus 1,
also irgendwie plus 3, so,
da habe ich es mal stehen lassen,
damit man gleich das Muster sieht.
Und dann macht man weiter. Jetzt guckt man sich an,
jetzt interessiere ich mich für T von N-minus
Da kann man sagen, okay, dann ist Tee von N minus 2,
ist das gleiche wie zweimal Tee von N minus 2,
minus 1, also Tee von N minus 3. Plus 1. Hast wieder schön geklammert hier.
Viermal, Klammer auf, zweimal T von N minus 3,
Klammer zu, plus 1, Klammer zu, plus 2 plus 1. Wieder ausrechnen.
Achtmal Tee von N minus 3. Plus 4 plus 2 plus 1. Muster,
wenn ihr euch überlegt, erste Abwicklung,
also von da nach da, in der ersten Zeile,
Erstabwicklung, zweite Abwicklung, dritte Abwicklung.
Also in der ersten Zeit, erste Abwicklung, zweite,
dritte. Wenn ich K mal abgewickelt habe,
wie wird das aussehen
Ja, zwei UK-Mahl, was war das? Ja,
genau. Zwei hochkam mal T von N-K plus was.
Genau. Und immer so weiter, ne?
Plus zwei UK minus eins, Cameos 2,
Cameos 3 und so weiter.
Das wäre jetzt auch erstmal
eine Vermutung
Dass man sagt irgendwie, naja, wenn ich
immer weiter abwickel, dann müsste doch das irgendwann rauskommen.
Das ist auch erstmal wieder nur eine Vermutung, die man
nochmal beweisen müsste mit vollständigen Luktionen. Dass man sagen muss,
ich nehme an, diese Formel, ich nehme an,
das kommt raus, wenn ich kaum mal abgewickelt habe.
Induktionsanfang sieht das wirklich so aus, wenn ich einmal abgewickelt habe.
Naja, dann steht hier zwei hoch eins,
also zwei mal Tee von N-1-1 plus zwei
hoch eins minus eins, also schon als zwei hoch null.
Das heißt, es sieht genauso aus wie das da.
Da weiß ich, dass das stimmt. Also nach einmal
abwickeln ist das richtig. Nach Karma abwickeln nehme ich jetzt an,
dass es dann so aussieht. Und jetzt zeige ich,
dass es nach Karplus eins mal abwickeln auch so aussieht.
Und dafür würde ich dann als als als erstes den die Induktionsannahme benutzen.
Dann nehme ich nämlich als erstes das T von Ende nach Karma abwickeln, so aussieht.
Und jetzt wickel ich noch einmal ab. Und dann muss
etwas rauskommen, was quasi genauso aussieht wie das hier.
Nur das überall, wo K steht, K plus 1 steht.
Und das ist auch tatsächlich so. Aber das müsste man
nochmal mit Induktion beweisen. Das schützt einen davor an der Stelle
was Falsches anzunehmen. Also wenn ich da jetzt irgendwie,
was wäre so ein typischer Fehler hier, vielleicht das so,
nehmen wir mal an, ich habe das plus 2 hoch 0 vergessen.
Ich habe halt gesagt so, ja,
das geht immer bis 2 hoch 1 oder irgendwie sowas.
Und dann würde ich das versuchen zu beweisen,
dann wird der Beweis nicht klappen in Induktion,
schon im Induktionsanfang würde das
nicht klappen
An der Stelle könnt ihr dann was falsch sagen.
Oder wenn man hier fälschlicherweise annimmt,
dass das endminus k minus eins ist oder irgendwie sowas.
Also Kleinigkeiten im Fehler, die man da irgendwie macht.
Das kriegt man dann durch den Induktionsbeweis halt raus.
Und ansonsten ist der Induktionsbeweis halt relativ einfach,
weil man ja quasi hier einfach nur nochmal das macht,
was man davor schon ein paar Mal gemacht hat, nämlich nochmal abzuwickeln.
Dann guckt man einfach nur, kommt da das Gleiche raus.
Also kommt da wieder die Formel raus, nur mit K plus eins
in allen Stellen. So, jetzt ist die Frage,
jetzt habe ich diese allgemeine Formel, nehmen wir mal,
ich habe die jetzt mit vollständigen Optionen noch bewiesen.
Wann bricht die jetzt ab? Wann kann ich aufhören?
Sonst muss ich das ja immer weitermachen,
aber wann kann ich aufhören
Genau, sehr schön. Die bricht ab, wenn
N-minus K gleich 1 ist. Hier ist die Abbruchbedingung,
dass gesagt wird, T von N ist eins,
also auf der rechten Seite kommt dieses T von N nicht mehr vor.
Ist eins genau dann, wenn N den Wert 1 hat.
Also wenn das Argument von T den Wert 1 hat, bin ich fertig.
Das heißt, wenn dieses N-minus K1 ist, bin ich fertig.
Oder anders formuliert, wenn Kardin Wert N-minus 1 hat.
Also bei K gleich N-minus 1,
weil dann habe ich N-minus N-minus 1,
also eins,
da breche ich ab
Ja, und dann sieht das so aus. Das war noch die allgemeine Formel,
die man, wie gesagt,
beforscht in die Auktion einmal beweisen muss, dann sage ich jetzt,
bei T gleich 1 bricht die Rekursion ab,
also wenn Cardin wird endminus 1 hat,
und dann setze ich überall, wo hier Car steht,
jetzt ein N minus 1 ein, und dann kommt das daraus.
Da steht jetzt überall einfach VKs in minus 1,
dann weiß man hier, das ist T von 1,
also ist das der Wert 1,
also steht da insgesamt 2 hoch 0 plus 2
hoch 1 plus 2 hoch 2 und so weiter,
bis hin zu 2 hoch N minus 1.
Also ist das die Summe von i
gleich 0 bis N minus 1 vor diesen 2 Hoch Is
Und entweder sieht man das jetzt sofort,
dass das quasi in Binärdarstellung 1-1-1-
1-1-1 ist.
Also ist das gerade der Wert 2-hoch-N-minus-1, was wir vorher auch schon hatten.
Oder man benutzt ja diese geometrische Reihe, die Formel.
Dann sieht man, dass das rauskommt. Zwei Wochen minus
1, durch zwei minus 1, also durch 1.
Und dann hat man genau das, was wir vorher auch hatten.
Und bezüglich O- und Täter-Notation ist das dann eben in Täter von zwei Hochenden.
Fertig. Also das waren die Schritte. Ich wickel ab,
bis ich irgendwie etwas finde, abhängig von K,
wo ich sage, nach K-Schritten sieht die Abwicklung so aus.
Dann beweise ich diese Formel noch mit vollständigen Loktionen,
was wir eben
nur kurz mündlich gemacht haben
Dann bestimme ich den Wert von K, bei dem
die Rekursion abbricht. Da gucke ich mir dann an,
wann bricht die Rekursion ab, setze dann das,
was da jetzt, wenn da in minus K steht und ich weiß,
bei 1 bringt das ab,
dann setze ich mir in minus K gleich 1 und löse das irgendwie zu K auf.
Wenn ich sowas habe wie N durch K und ich weiß,
das bricht bei dem Wert 1 ab,
dann weiß ich N durch KS1, dann weiß ich irgendwie,
K muss N sein.
Setze ich ein und dann versuche ich irgendwie zum Ergebnis zu kommen,
so wie eben, dass ich dann irgendwie bei dem 2 hoch N minus 1 bin.
Und eventuell letzter Schritt, wenn das jetzt nicht so aussieht wie 2 hoch
N minus 1 oder wenn das irgendwie was Komplexeres ist,
dann muss ich dann eventuell noch mal abschätzen,
wie sieht das bezüglich der O- und Omega-Notation aus.
In dem Beispiel musste man das nicht machen,
bei anderen Beispielen muss man
das manchmal machen
Fragen. Die Frage war, ob das jetzt so die
Methode ist, die man generell für alles verwenden kann.
Also die funktioniert zumindest besser als bei der ersten,
wo man gesagt hätte,
ich rechne ein paar Werte aus und gucke dann,
ob ich auf irgendwas komme, weil man halt manchmal nichts sieht.
Also relativ häufig sieht man nicht so. Und die,
gute Frage, funktioniert die immer? Eigentlich ja,
ich kann bestimmt Fälle konstruieren, wo das vielleicht mit
dem Induktionsbeweis und so nicht so einfach ist.
Aber so prinzipiell, ja, klappt das irgendwie mit Abwickeln
und so
Sonst noch Fragen. Alles gut. So,
dann war die Rekursion ja relativ einfach. Das war so
Tee von N gleich zweimal Tee von N minus eins.
Das ist einfach, solche Rekursionen hier, die sind schon fieser.
Da sage ich irgendwie dreimal Tee von N Drittel plus eins
durch N. Wo kann das auftreten? Eigentlich relativ,
also kann man sehr schnell Beispiele für konstruieren.
Ihr habt ein Arry der Länge N. Ihr teilt das in
drei Teile
Und rechnet auf diesen einzelnen Teilen rum. Dann ist jede Instanz
ein Drittel groß. Ihr rechnet dreimal, also dreimal T
von N, Drittel. Und dieses Plus-1 durch N,
okay, das wäre jetzt irgendwie was,
wo man dann, nachdem man die Rekussionsaufrufe hat,
vielleicht nochmal was zusammenfügt oder irgendwie sowas eins durch Ändere zugegebenermaßen eher selten auf,
aber sowas wie Endquadrat oder irgendwie sowas wäre jetzt durchaus üblich.
Müsste man irgendwie das ändern und machen.
Ja, genau. Frage war gerade,
was man jetzt mit diesem Enddrittel macht, weil irgendwie,
wenn ich jetzt mit N gleich 8 komme oder so,
funktioniert das nicht
Da geht man immer von sowas aus, entweder Abrundung oder Aufrundung.
Man spart sich nur, das hier aufzuschreiben,
weil das tut sich nachher quasi nichts bei der Unnotation.
Also du willst ja nur, dass irgendwie abwickeln und so,
auch das Abwickeln zum Beispiel, das funktioniert auch nur,
wenn man jetzt irgendwie davon ausgeht,
dass man dann lock so und so viele Male abrundet und all sowas.
Aber da kann man immer von ausgehen, also das tut sich quasi nachher im Ergebnis nichts.
Wenn man das Ganze schränk formal machen will,
dann muss man das nochmal mit Sternchen irgendwo anmerken,
dass man dann sagt, so,
jetzt sind das eigentlich nur so und so viele Schritte
und ich muss hier eigentlich ab und aufrunden und so,
aber bezüglich der O- und Omega-Notation tut sich das nicht,
weil es dann immer so ein Unterschied von einem Schritt
ist oder irgendwie sowas
Genau, das kann man auch wieder mit Substitutionsmethode machen.
Das ist schon aufwendig. Dann haben sich nette Leute was überlegt,
damit man das nicht alles immer ständig abwickeln muss.
Und dann gibt es dieses sogenannte Master-Theorie. Und mit dem Master-Theorien,
das wollen wir jetzt hier auch nicht beweisen,
wir wollen es einfach nur benutzen,
mit dem Master-Theorien lassen sich solche Rekurrenzgleichungen in vielen Fällen sehr einfach lösen,
also was heißt lösen,
da löst man die eigentlich gar nicht so,
mit dem Master-Theorien lassen sich von solchen Rekurrenzgleichungen in vielen Fällen einfach die Lösung ablesen.
Also ich mache einen Vergleich und dann weiß ich,
wie das Ergebnis aussieht
Und das Mastertheorium selbst sieht zuerst ziemlich fies aus,
wenn man es sich ein bisschen länger angeguckt hat,
dann ist das nicht mehr ganz so schlimm.
Aber am Anfang sieht es fies aus. Also es gilt für Rekurrenzen dieser Form
. Einmal schon vorweg, es gilt nicht für alle,
aber für einen relativ großen Teil kann ich damit erschlagen.
Und zwar, ich habe irgendwie so eine Abbruchbedingung bei N
gleich 1 und für größere Ends habe ich als Rekursionsgleichung N
mal T von N durch B plus F von N.
Das B gibt quasi an, in wie viele Teilprobleme ich
das zerlege. Also wie groß das B gibt an,
wie groß die einzelnen Teilprobleme sind
Also en halbe Gruß, ein Viertelgruß, ein Drittelgruß, irgendwie sowas.
Das A gibt an, wie oft ich auf Teilproblem arbeite.
Also ich kann zum Beispiel beim binären Suchen,
da wir A gleich 1 und B2,
weil ich einmal in ein halb so großes Problem reingehe.
Und das F von N, das ist dafür da,
dass ich die Ergebnisse vielleicht noch zusammenfügen muss oder am Ende
was zerlegen muss oder sowas.
Dass ich dann sage, wenn ich beide Teilprobleme gelöst habe,
dann brauche ich danach vielleicht noch N-Quadrat viele Schritte,
um die irgendwie zusammenzufügen
Dafür ist das da. Und hier steht auch,
was er eben schon angemerkt hatte,
N durch B wird irgendwie als Abrundung oder Aufrundung verstanden,
Tee von N ist eigentlich nur über die natürlichen Zahlen definiert,
aber das sind so Besonderheiten,
die brauchen wir jetzt eigentlich gar nicht so richtig.
Also man kann das gleich einfach durchexerzieren, ohne auf sowas großartig zu achten.
Aber wenn man da gerade dann denkt, dann... So,
und was man jetzt macht, und das ist jetzt,
das sieht am Anfang halt ein bisschen schwierig auf,
ich mach das mal hier auf,
was jetzt getan wird ist,
man will jetzt ja tief von N einsortieren und die zwei Funktionen,
die man jetzt vergleicht miteinander,
sind einmal
dieses F von
Also der da, F von N. Und man guckt sich die Funktion an,
die wie folgt entsteht, N-Hoch, Lugarithmus zur Basis
B von A. Das hat halt was damit zu tun.
Er meinte das ja vorhin schon mit diesem Baum, Loghithmus zur Basis
B von A, das hat was irgendwie mit der Baumtiefe
zu tun und wie auf die Verzweige und sowas.
B ist ja die Größe der Type oder durch B
wird irgendwie hier die Größe der Teilprobleme definiert durch A,
wie oft ich darauf arbeite.
Und dieses Log B-A, das hat halt damit was zu tun.
Und man guckt sich halt die Funktion an N-Hoch,
Log B-A und die Funktion F von N.
Und was man im Grunde genommen macht,
ist, man guckt sich an,
welche von beiden
größer ist
Und das Tee von N verhält sich dann so wie die größere von beiden.
Mit gleich noch zwei Einschränkungen, aber erstmal das ist so die Grundidee.
Hier steht nämlich, wenn das F von N,
kleiner gleich diesem N-Hoch-Lock-BA ist, dann ist also das N-Hoch-Lock-BA größer,
dann verhält sich das Tee von N so wie das größere.
Wenn, wie hier im dritten Fall, dritter Fall jetzt,
wenn das F von N größer gleich dem N-Hoch-Lock-BA ist,
das ist das F von N das größere,
dann verhält sich das T von N wie das F von
N,
also auch wieder wieder wieder
das größere
Und jetzt gibt es halt zwei, drei Einschränkungen, nämlich,
wenn F&N und N hoch LogbyR, wenn die sich gleich verhalten asymptotisch,
also wenn das ein Täter von dem ist,
dann ist T von N, jetzt würde man normalerweise warten,
okay, jetzt verhält es sich wie eins von beiden,
aber dann gibt es halt diesen Unterschied, dann sagt man,
dann ist es in Täter von Endo LogbyR,
mal genommen noch mit Logorithmus 2 von N.
Muss man jetzt in den Beweis reingehen,
wenn man verstehen will, warum das noch dazukommt,
aber hier an der Stelle fällt es sich jetzt eben nicht so wie das Größere von beiden,
weil es gibt ja jetzt kein größeres, die sind beide gleich groß,
sondern das verhält sich dann so wie eins davon,
hier ist auch egal,
ob ich Endo LogbyR hinschreibe oder F von N,
aber es verhält sich so wie eins davon,
multipliziert mit Log 2 ein
Das ist die eine Einschränkung. Die zweite Einschränkung ist,
wenn F von End größer ist als Omega, von LogBR,
dann gilt das nur, wenn zusätzlich noch diese sogenannte Regularitätsbedingung gilt.
Die gucken wir uns nächstes Mal nochmal kurz ein bisschen genauer an,
nur dass ihr da seht schon mal, okay,
da gibt es noch so eine Einschränkung.
Für heute können wir die einmal nochmal ignorieren.
Und die dritte Einschränkung ist noch,
es geht nicht einfach nur darum,
dass es kleiner oder größer oder sowas ist,
sondern hier ist immer noch dieses Minus-Epcylon oder Plus-Epcylon drin
Das führt dazu, man sagt dann, dass es polinumiell größer ist.
Es gibt dann tatsächlich einen polinumiellen Unterschied. Für uns in
der Ausführung heißt das nur, wir bestimmen das F&N,
wir bestimmen N-Log BR und wir gucken,
ob wir irgendwie so einen Wert Epsilon finden können.
Das sieht man meistens relativ einfach, ob es den gibt oder nicht.
Sodass finde ich, dass sie oben im Exponenten abziehe,
das trotzdem noch da drunter liegt. Beispiel, also auch so,
was ihr mitnehmen solltet, ich bestimme diese Funktion N-Hochlock BR,
ich bestimme das F&N, ich gucke bei beiden,
was ist jetzt größer und das T-Von-N verhält sich so.
Das ist so die grobe Idee und dann
Es langt, wenn ich hier einen Apps finde, für einen Appsilon.
Weil es gibt ganz bestimmt auch welche, für die das nicht mehr gilt.
So, Beispiel, damit man das ein bisschen besser versteht.
Rechts steht nochmal die Gleichung, wie sie im Mastertheorie auftritt.
Links ist die Rekurrenzgleichung, die wir eben hatten.
Damit das nicht zu doll durcheinander geht,
habe ich das hier mal zig Strich genannt.
Hier ist jetzt das C. Und oben ist der Fall,
der jetzt gleich tatsächlich auch zutreffen wird, nämlich dieser erste Fall.
Was macht man jetzt? Man guckt sich jetzt an,
dass A, Pattern Matching, das AS 3,
B ist auch 3 und F von N
ist eins durch
Also habe ich Log BR, Log 3-3,
das ist eins, F von Ende ist eins durch N
und jetzt vergleiche ich F von N mit F von N
vergleichen mit N hoch 1 minus Epsilon.
Das muss ich mir angucken. Gibt es irgendwie so ein Epsilon,
der hat das F von N in N hoch 1 minus Y drin ist?
Und wenn ich jetzt Epsilon 2 wähle, dann ist das so.
Dann habe ich nämlich F von NS 1 durch N,
wenn ich Epsilon 2 wähle,
steht hier auch eins durch N,
dann steht da eins durch einen enthaltenen O von 1 durch N,
das ist so,
weil sie da beide gleich und
der Mischung fertig
Liegt also der erste Fall vor, wie auch beim Abwickeln und dann
habe ich hier die Schlussfolgerung, darf ich dann ziehen,
also so wie es hier auch steht, Tee von NS-Element von
TTAN Hochlockey Arm. Genau. Jetzt kann man sich noch
ein Beispiel für das zweite angucken und für das dritte.
Das zweite, es geht ähnlich einfach hier,
da bestimmt man dann auch das F von Ende und das End of Locke BR, guckt,
ob das in Täter von End of Locke BR ist,
kann man wieder mit dieser Liebesbildung machen oder so.
Und wenn das gegeben ist,
dann kann man sofort Schlussfolger in Tee von Ende ist,
in dieser Komplexitätsklasse da
Und der dritte Fall, der wird eben ein bisschen schwieriger,
weil man da nochmal diese Regularitätsbedingungen prüfen muss.
Zusätzlich. Wenn denn überhaupt das hier gilt. Ja,
und das Problem bei diesen Mastertheorien ist, ich hatte ja gemeint,
hier mit diesem Epstilon, da erreiche ich etwas,
was man so einen polinomiellen Unterschied nennt.
Und es gibt halt Rekurrenzgleichung, die zwar diese Form haben,
bei denen aber F von N und N hoch Lock BA minus Y,
bei denen die keinen polinomiellen Unterschied haben.
Und dann funktioniert das nicht. Oder wenn die Regularitätsbedingungen nicht gilt,
aber die gilt bei den Sachen, die wir uns angucken,
fast immer
Beispiel bei der Gleichung, die jetzt gar nicht so böser aussieht,
zweimal Tee von N halbe, also ich haltiere irgendwie,
dass Arry arbeitet auf beiden Hälften und beim Zusammenfrügen brauche ich jetzt vielleicht nicht Endschritte,
sondern end mal Login-Schritte, da funktioniert das schon nicht.
Weil da habe ich als F von N dieses N
mal Login und als N-Hoch-LogBA, BS2AS2, das heißt,
da kommt N hoch 1 raus und da muss ich irgendwie
N mal Login vergleichen mit N-Hoch 1,
minus oder plus Epstilon.
Und das funktioniert nicht, weil Logarhythmus von N,
keinen polymuellen Unterschied erzeugt.
Deswegen kann ich die beiden in dem Mastertheorie im Setting
nicht vergleichen und dann hilft mir das dann nicht,
da musste ich dann
irgendwie abwickeln oder so
Genau so wollen wir dich beweisen, wenn ihr das mal nachlesen möchtet, steht im Kormen.
Das ist irgendwie so ein 5, 6, 7 Seitenbeweis.
Genau, und der macht dann da so mit Bäumen,
um das zu illustrieren, wie das halbiert wird.
Gut, Fragen. Ja, also die Frage war gerade,
ob das Äpfelon so eine Differenz ist, sodass die beiden,
also das F von N und das andere,
dass die gleich werden, nicht zwingend gleich,
sondern es muss halt nur gegeben sein, dass du Hier,
du guckst dir N hoch Lock BA an.
Also du willst ja quasi wissen,
liegt das F von N unter dem N hoch Lock BA.
Und es soll aber nicht einfach nur unter dem N hoch Lock BA liegen,
sondern ich muss von dem N hoch Lock BA noch
irgendwie etwas polemielles quasi abziehen können,
sodass es weiterhin da drunter liegt.
Also dieses Minus Äpzilon ist ja quasi N-Hoch Lock BA geteilt durch N hoch Äpzilon.
Also teile ich das quasi nochmal durch Andrew Habson und dann muss was rauskommen,
was weiterhin, wo das F von N weiterhin drunter liegt.
Und das ist eben bei dem Setting von eben,
mit diesem N-My Lock N und Ende,
da ist das halt nicht gegeben.
Da kriege ich
den Vergleich halt nicht hin
Aber ansonsten klappt das bei ziemlich vielen Rekurrenzgleichungen. Ob das
heißt, dass die mindestens zwei Ends auseinander liegen müssen?
Was meinst du mit zwei Ends? Sowas wie Endquadrat oder so?
Nee. Nee. Du sollst dir nicht einfach irgendeine App,
du sollst ein Epstilon finden, du sollst ein Epstilon finden,
sodass das gilt. Du nimmst jetzt nicht irgendeins und sagst,
guck mal, dafür gilt es nicht,
also kann ich verschlussfolgern, sondern du sollst eins finden,
für das das gilt.
Ja,
eins reicht
Fragen zum ersten? Ja. Ich glaube, ich habe
die gleichen Fragen mäßig anders kommentiert. Man muss das ausziehen.
Nee, reelle Zahlen. Also einfach irgendeinen Zahlenwert. Also
reelle Zahlen bringt, glaube ich, nicht so viel,
aber so kannst du auch 0,2 nehmen oder irgendwie sowas.
Also hier zum Beispiel bei dem Beispiel,
da hätte man für das Apple noch durch zwei nehmen müssen,
da hätte es auch irgendwie 0,1 nehmen können oder so.
Dann hast du die Frage,
ob N hoch minus eins enthalten ist in O von N
hoch 0,9 und das ist auf jeden Fall gegeben
Hat er ja auch gerade gefragt, ob er so eine ganze Zahl sein muss.
Nee, Epsilon kann eine beliebige Zahl sein. Also nur
, bitte? Alle positiv bewerten. Ja, genau,
positiv, genau. Hier für ein Epsilon größer Null.
Also es ist ein positiv sein. Und ich glaube,
reelle Zahlen braucht man nicht, aber halt so 0,2,
0,3, irgendwie sowas.
0,005 auch, ja, das kannst du auch nehmen.
Behauptung, dass das für einige nicht funktioniert,
wenn ich das jetzt auch nicht so direkt so baue.
Ja, nee. Also das siehst du dann ja auch,
wenn du es für diese hier machen willst,
wenn du es für die hier machen willst,
dann wirst du beim Ausführen feststellen,
dass das nicht funktioniert
Also einfach selber. Ja. Ich glaube,
beim nächsten Ding sind sie,
also nächstes Mal sind sie, glaube ich,
auch auf den Folien drauf, aber bei denen,
die ich euch jetzt gegeben habe, klappt das.
Das ist der praktisch, der hat vielleicht auch das ganze Haus.
Das fällt leider ein bisschen in die Regulierung.
Ich habe dann also quasi so eine zweite Leiche erzählt,
die die Güte dran hat.
Die Frage war, wie das mit der praktischen Anwendung ist.
Sehr oft anwendbar. Also die meisten rekursiven Algorithmen lassen sich
damit analysieren
Lass uns noch fragen. Erstens, zweitens, gut. Genau,
dann noch einmal kurz eine Zusammenfassung,
dann sind wir auch fertig, übliches Vorgehen, also,
was wir machen wollen, kriegen Probleme, wollen Algorithmus finden,
der es löst, dann müssen wir die Korrektheit beweisen,
Laufzeit ermitteln und die beweisen und eben unter Umständen Platzbedarf, wenn er das auch interessiert.
Und was wir halt so gemacht haben und auch in der Zukunft machen wollen,
für erstens, also gegeben ein Problem finden Sie einen Algorithmus,
der es löst, da wollen wir uns irgendwie Algorithmentechniken angucken,
uns mit Algorithmenentwurf beschäftigen und die, die wir bisher so hatten,
die sind noch alle relativ einfach,
sowas wie eine lineare Methode, ich gucke mir alles an,
Das war eine Brut-Force-Technik im Grunde genommen.
Binäre Suche, das ist nicht mehr so Brut-Force,
aber noch ein ziemlich einfaches Verfahren, das ich irgendwie immer
halbiere und dann nur noch mit der einen Hälfte arbeite oder den Suchraum komplett durcharbeiten.
Also letztes Mal hatten wir dieses Beispiel mit dem Timemeng,
dem Timemengen-Summenproblem, wo man sich dann einfach den kompletten Suchraum angeguckt hat,
das ist halt das,
was man bei NPV-ständigen Problemen immer machen kann oder was man halt trotzdem versucht,
irgendwie anders und sinnvoller zu machen.
Ja, geht fast immer, ist aber teuer,
den Suchraum komplett zu durchsuchen,
ist eigentlich
immer exponentiell
Dann Korrektheitsbeweise. Da gibt es nicht,
also hier wollen wir auch weitere Algorithmentechniken kennenlernen,
die wir dann auf Probleme anwenden können.
Das ist auch schon, da muss man auch schon kreativ
sein, um Probleme irgendwie zu lösen.
Korrektheitsbeweise genauso. Auch da gibt es irgendwie kein generelles Verfahren,
sondern man muss das halt für jeden Algorithmus irgendwie neu machen.
Genau. Schleifenden Varianten haben wir uns heute angeguckt.
Weitere Techniken gucken wir uns dann an.
Und Laufzeitanalyse haben wir mittels O-Notationen gemacht. Wir haben uns
die Laufzeitanalyse einfacher sequenzielle Algorithmen angeguckt,
für sequenzielle Algorithmen ist es meistens auch relativ gut zu
sehen,
wie viele Schritte man so braucht
Natürlich auch umständlicher werden. Und heute haben wir uns mit
dieser Laufzeitanalyse rekursiver Algorithmen beschäftigt. Und mit denen kann man
halt gerade diese Klasse von Devide & Conquer verfahren,
die wir uns nächstes Mal auch angucken wollen.
Quasi die Laufzeitanalyse von denen machen. Und die drei Methoden,
die wir kennengelernt haben, ist eben raten und beweisen,
abwickeln und da auch beweisen.
Und das Mastertheorien zu benutzen. Genau. Da steht das nochmal,
damit es wirklich dann auch alle mitnehmen mit diesen Kenngrößen.
Und da nochmal, was wir nächstes Mal machen wollen.
Die Weite in Conquer wollen wir nächstes Mal machen,
als so ein ganz klassisches Algorithmenverfahren.
Da wollen wir uns dann auch den Merch-Short-Algorithmus angucken und
den Quick-Short-Algorithmus,
glaube ich
Da,
insbesondere da kann man halt mit diesen Rekurrenzgleichung gut arbeiten,
wenn man ein bisschen Gefühl dafür hat,
dann kann man bei ganz vielen Gleichungen,
weil üblicherweise halt nicht sowas mit eins durch N haben oder so,
kann man üblicherweise für ganz viel Gleichung schnell sehen und welche Komplexitätsklasse,
die ungefähr fallen.
Und das ist dann ziemlich angenehm. Genau,
dann wollen wir noch einmal nächstes Mal ein bisschen noch was zur Mastertheorie machen,
nämlich diesen dritten Fall uns einmal mit einem Beispiel kurz angucken
und als nützliches Hilfsmittel variablen Transformationen kennenlernen.
Das führt nämlich dazu, dass man nicht nur solche Rekurrenzgleichungen
mit TVN gleich TVN Viertel oder so attackieren kann,
sondern auch solche wie TVN gleich Wurzeln.
Das kann man auch angreifen mit Mastertheorien.
Braucht man aber diese variablen Transformationen für
Ja, dann ist, genau, dann ist sehr gutes Timing.
Habt ihr noch Fragen? Erstes, zweites.
Aber warte mal, ich bewege mich gar nicht.
Der bewegt sich. Das ist aber nicht der Livestream,
oder? Ich bewege mich im Livestream. Kim,
was hast du getan? Ich bewege mich im Livestream.
Okay, ich stehe immer noch nicht.
Jetzt habe ich gerade die, das ideritiert mich total.
So, hattet ihr noch irgendwelche anderen Fragen,
außer guckt mal, wie du im Livestream aussiehst.
Gut, der hat mal eine Viertelstunde Pause und danach
rechnen wir noch ein bisschen rum und vertiefen das nochmal,
was wir eben gemacht haben.
Dann ist Viertelstunde Pause