Okay. So, es kann losgehen. Wir, ja,
sind in der Vorlesung Algorithmen und Datenstrukturen und gucken uns gerade das Okalkül an.
Das war die zweitletzte Folie aus der letzten Vorlesung.
Wir haben uns angeschaut hier an diesem Beispiel, wie das Wachstum verschiedener Funktionen aussieht.
Und allein an diesen wenigen Zahlen kann man sehen,
dass dieses Wachstum gravierend ist für ein Laufzeitverhalten eines Algorithmus.
Also wir haben hier verschiedene Klassen. Wenn wir jetzt überlegen,
einen Algorithmus benutzen, Zeit, proportional zu zum Beispiel N-Quadrat,
dann bedeutet das für wachsende Eingabe N,
dass wenn die jetzt wächst von zehn Daten, Punkte,
was immer es ist, auf 1000 auf eine Million,
dass sich dann entsprechend natürlich die Laufzeit quadratisch verhält.
Also 101 Million 10 hoch 12. Und man sieht sehr schnell,
dass für große Eingaben Laufzeiten ja häufig schon im Bereich von N-Quadrat,
N durch 3 kritisch werden können, aufgrund dieses Wachstumsverhaltens.
Deswegen untersuchen wir Algorithmen gerade im Hinblick auf dieses Wachstumsverhalten.
So, dann haben wir uns die Definition des Okalküls angeschaut
Die sehen sie hier nochmal. Was sie besagt ist,
dass sie zwei Funktionen, F und G in Relation zueinandersetzt. Und zwar gilt,
dass F&N gleich O von GVN ist, genau dann,
wenn zwei Konstanzen existieren, C und N.0,
sodass für alle Andy dann größer sind als N.0, 0,
kleiner, gleich F&N, kleiner, gleich C.M.G. von N ist.
Das ist die Definition noch einmal des Okalkühls. Und am besten ist,
wenn man vom Ulkakül nicht diese Formel im Kopf hat,
sondern das Bild, was sich dahinter verbirgt.
Und das Bild ist nichts weiter, als dass man eine Funktion hat.
Hier ist für uns in der Regel immer die Zeit,
Entschuldigung, die Eingabegröße. Und hier ist die Zeit,
ja. Unsere Funktion zeigt irgendein Wachstumsverhalten, ja.
Und das ist also die reale Zeit des Algorithmus, die wir nicht genau kennen.
Und das wäre also unsere Funktion F hier von N.
Und wir haben eine andere Funktion. Es wäre unsere Funktion G von N. Und wir können dann sagen,
dass F&N höchstens von Ordnung geht von N ist,
wenn es einen Punkt gibt, also ein N-0,
sodass für alle Punkte jenseits von dem N0,
also ab hier nach da gesehen,
die Funktion F von Ende immer kleiner,
gleich geht von Endes.
Wobei wir die Funktionen auch noch mit einer beliebigen konstante multiplizieren können.
Okay, das Wichtige dabei ist eben, es ist asymptotisch,
das muss nur ab diesem N0 gelten.
Alles, was davor ist, ist weniger interessant für uns.
Okay, neben dem Groß-O,
was wir hier in der Vorlesung am meisten verwenden werden,
gibt es noch ein paar weitere, sehr ähnliche Definitionen.
Die stehen hier unten und sie sehen hier immer,
worin sich die Definition unterscheidet.
Den Rest habe ich nicht mehr aufgeschrieben. Also einen Klein-O
verwendet man dann,
wenn die Schranke echt ist
Das bedeutet, dass für alle möglichen Konstanten diese Funktion F
und ein kleiner sein muss als zehnmal G von N.
Und dann gibt es Omega, Omega verwenden wir für untere Schranken. Das heißt,
hier dreht sich halt das Kleine gleich in ein größer Gleichzeichen
um und das Kleine Omega ist genauso wie das Kleine O. Das heißt,
es muss hier das größer, gleich wird es zu einem echt größer.
Das heißt, die Funktion F und N muss für alle
möglichen Konstanten immer größer sein als C-MAG von N. Okay,
so und dann haben wir noch das Täter und das Täter
ist nichts weiter als O und Omega zusammen.
Das heißt, es gibt zwei Konstanten,
das C1 mal G von N,
kleiner gleich F und N,
kleiner gleich
Einmal geh von NS. Das heißt, die Funktion F&N
ist von gleichem Wachstum, wie die Funktion geh.
Wir können die über zwei Konstanten eingrenzen und die Funktion F
liegt dann also genau dazwischen. Also Groß-O für eine obere Schranke,
Groß-Omega für eine untere Schranke, Täter,
wenn das Wachstum in etwa Gleiches und das Klein-O und das Klein-Omega,
wenn man zeigen will, dass etwas echt stärker oder schwächer wächst,
das werden wir aber in der Vorlesung eigentlich nicht verwenden.
Okay, das nur noch mal zur Definition des Okalkühls.
Das gibt es eine ganze Menge von Regeln,
wenn man mit dem Okalkühl arbeiten will und rechnet.
Und hier sind so ein paar grundlegende Rechenregeln fürs Okalkühl
Also eine Funktion ist zum Beispiel immer in der gleichen Größenordnung,
wie die Funktion selber. Ja, das können Sie
direkt einsetzen in die Definition und können dann bestimmen,
was C und C und N 0 ist.
Und das ist natürlich noch die relativ einfache Regel,
was viel wichtiger ist, ist, wie man Funktionen miteinander verknüpft.
Also wenn zum Beispiel F und G beide von der Größenordnung der Funktion Groß-F ist,
dann ist die Summe der beiden Funktionen F plus G,
auch von der Größenordnung von F,
Konstanten werden vernachlässigt, das ergibt sich schon aus der Definition. Das heißt,
wenn die Funktion F in der Größenordnung O von Großef ist und C eine Konstante ist,
dann können wir natürlich die Funktion F auch mit C
multiplizieren und es ändert nichts an der Größenordnung der Funktion.
Dann gibt es so etwas wie, ja, Transitivität.
Das heißt, wenn F von der Größenordnung Großef ist und
G ist von der Größenordnung Klein F,
können wir die auch hintereinander schalten und dann ist G auch von der Größenordnung groß.
Das ist einfach nur eine obere Schranke einer oberen Schranke.
Ja,
das gilt dann natürlich
Trotzdem. Wenn man multipliziert, geht das auch.
Also wenn F von der Größenordnung Großef ist und G von der Größenordnung GroßG,
wenn wir das Produkt der beiden Funktionen bilden und dann ist
das auch in der Größenordnung des Produkts der beiden Schranken.
Und ja, schließlich, wenn wir ein Produkt von Funktionen
haben, dann können wir eine Funktion auch herausziehen.
Allerdings müssen wir da aufpassen mit den Vorzeichen. So eine
Funktion könnte ja ein negatives Vorzeichen haben und dann würde das
nicht mehr stimmen und deswegen muss man hier den Betrag von der Funktion F nehmen.
Okay, so ja, das sind schon die wichtigsten Regeln,
wenn eine Funktion natürlich durch eine andere generell beschränkt ist,
dann können wir natürlich
auch die nehmen
Als obere Schranke. So,
das sind so ein paar Rechenregeln und wenn man sich überlegen will,
warum gelten die denn jetzt, dann kann man das relativ leicht nachweisen.
Unseren Nachweis funktioniert dann, indem sie einfach die Definitionen verwenden
und das setzen sie ein und sie zeigen dann einfach,
dass es wieder entsprechende konstanten C und R0 gilt, dass die entsprechende Rechenregel gilt.
Das habe ich Ihnen hier nur für ein Beispiel aufgeschrieben,
ist also zu dem, hier zu dem Regel Nummer 5,
ja, diese Produktregel hier, da setzt man dann,
also wir wissen,
dass F gleich O von Groß-F ist und G ist gleich O von Großg und da setzen wir das in die Definition ein,
das heißt, dann wissen wir,
es gibt konstanten N0 und 10-0,
sodass für alle N größerreich N0, F&N,
kleiner gleich 10-0 mal Große von N.
Es ist einfach nur die Definition des O-Kalküls hier verwendet.
Und für G können wir das Gleiche machen,
da haben wir jetzt irgendwie zwei andere Konstanten.
Da haben wir jetzt N1 und C1, sodass für alle N
größer gleich N1 GVN N, kleiner gleich C1 mal Großgeh von Ennis.
So, und jetzt gucken wir auf der rechten Seite,
wofür möchten wir eine Aussage machen? Wir möchten wissen,
wie stark wächst denn F mal G, weswegen definieren wir eine neue Funktion,
dass die Funktion H und sagen, Haar von Ennis, gerade dieses Produkt F&N mal GVN.
Und dann müssen wir uns jetzt überlegen,
was sind jetzt die Konstanten, sodass wir zeigen können,
dass das beschränkt ist durch Groß-F mal Groß-G. Naja,
dann können wir uns schnell überlegen, dass wir eine Konstante wählen,
die einfach das Maximum, also eine konstante N2,
die das Maximum ist von N0 und N1, weil wir wissen,
ab N0 und für alles Größere gilt das F&N kleiner gleich 10-0 mal Groß-F&N ist.
Und ab N1 und alle größeren N gilt eben das GVN, kleiner gleich, C1 mal Großki von Ennis. Dann nehmen wir also jetzt ein,
Maximum von den beiden,
das nennen wir N2 und sagen für alle Andy größer sind als N0 und N1,
gilt dann, dass das Produkt F von NMAG von N,
kleiner gleich und dann C00 mal F&N und mal C1 mal geh von Nnis,
weil das F&N kleiner gleich 10-0 mal F&N ist und dieses geht von ein kleiner gleich C1 mal geh von N. Okay,
so, dann können wir das ein bisschen umformen,
wir nehmen die beiden Konstanten zusammen,
wir wählen also eine neue Konstante,
die nennen wir C2,
die ist dann das Produkt aus C0 und C1 und dann
ist das gleich C2 mal F und MAG von N und das ist genau die Definition des Okalküls für die neue Funktion H,
die das Produkt der Funktion F und G war
Das ist schon alles. Und auf diese Art und Weise
kann man einfach die Plausibilität dieser Rechten regeln.
Relativ einfach und schnell überprüfen. So,
die kann man dann auch ein bisschen anwenden und findet dann ein paar ganz wichtige Regeln heraus,
die man dann so ansetzen und anwenden kann,
wenn man später mit dem O-Kalkül arbeitet.
Hier sind davon ein Paar. Also wir werden bei der Analyse von Algorithmen
häufig Polynome haben und bei einem Polynom Welches ein Grad M hat,
also wo der höchste, der höchste Exponent, der vorkommt,
M ist, dann wissen wir, dass dieses Polynom vom Grad,
also O von N hoch M ist.
Das ist der höchste Exponent, immer der zählt,
weil für alle anderen Exponenten, die noch in dem,
in der, in dem Polynom vorkommen,
die vom Wachstum immer beschränkt sind durch das Polynom,
durch den Therm mit dem höchsten Exponenten.
Ja, wenn wir Funktionen haben im niedrigeren Wachstum,
hier wird zum Beispiel 3N-Quadrat plus 17 mal Wurzeln,
ja,
dann wissen wir,
das Wurzelenders wächst viel langsamer als Endquadrat und das wäre dann
also beschränkt durch den vorderen Therm und das
wäre dann O von N
ein Quadrat
Okay, so. Manchmal hat man sehr große Konstanten und
das ist einer der wirklichen Nachteile des Okalküls.
Also wir hätten zum Beispiel so eine Funktion, F&N gleich zehn hoch,
300 mal N, plus zweimal N Login. Dann würde ja,
also für jedes, für uns eigentlich sinnvolle N,
dass hier vorne der viel, viel größere Therm sein,
weil wir gar nicht so große N verwenden würden, ja.
Aber trotzdem, wir betrachten hier nur das Wachstum der Funktion,
unabhängig von diesen Konstanten.
Das heißt, der, der ein stärkeres Wachstum zeigt,
ist der Hintere.
N Login wächst stärker
N-Log-N-Wags stärker als die lineare Funktion N. Und deswegen ist das
hier in O von N-Log-N. Die Konstanten, die lässt man
ja immer weg. Und hier muss man ein bisschen aufpassen,
Konstanten im Exponenten darf man natürlich nicht weglassen.
Also wenn da steht, wenn die Funktion fünfmal endest,
dann ist das O von N, dann können wir das fünfmal auch weglassen.
Aber wenn wir eine Funktion haben, zwei hoch,
zweimal N, dann steht das N im Exponent und dann
können wir dich einfach hier diesen Taktor weglassen,
weil das tatsächlich zu einem ganz anderen Wachstum führt.
Also zwei hoch zwei N ist das Gleiche wie 4 hoch N und 4 hoch
N ist eine ganz andere Wachstumsklasse als 2 hoch N.
Also mal aufpassen, Konstanten im Exponenten darf man nicht weglassen.
Die Ziel spielen im Okalkül eine Rolle.
Es sind nur konstante Faktoren, die vor der Variablen,
also in der normalen Position hier stehen, die wegfallen.
Was auch noch wichtig ist, ist,
wenn wir Logarithmen haben, wir haben häufig Logarithmen,
Logarithmen haben wir eigentlich zu irgendeiner speziellen Basis.
Also wir hatten zum Beispiel eine Funktion zur Basis 10,
wo der Logarithmus zur Basis 10 ist von N.
Und es gibt ja den Basiswechselsatz,
wo wir den Logarithmus von einer Basis in einem Logarithmus
zu einer anderen Basis umrechnen können
Also wir können den Lugorithmus zur Basis 10 von N umrechnen
in einen Lugorithmus, zum Beispiel zur Basis 2 von N.
Und dann müssen wir das dividieren durch den Lugorithmus zur Basis
2 von 10. Ja, es ist so eine Logorithmenregel.
Und dieser hintere Teil, also so eins durch den Lugorithmus
zur Basis 2 von 10, ist natürlich eine Konstante.
Und konstanten vor den Thermen, hier können wir weglassen,
die können wir vernachlässigen. Und deswegen ist das hier
O von Lugorithmus zu Basis 2 von N. Das bedeutet,
wir können im Okalkalkül quasi die Basis beliebig austauschen,
ohne dass wir das Wachstum der Funktion ändern.
Und in dem Sinne lassen wir im Okalkül eigentlich die Basen
auch immer weg
Also im Okalkül innerhalb des Okalküls finden sie eigentlich in der Regel
keine Angabe der Basis des Logohythmus, weil es spielt keine Rolle.
Es ist nur eine Konstante. Ja, damit muss man
ein bisschen Übung bekommen, um damit nachher Laufzeiten abschätzen zu können.
Ich möchte noch zwei, drei Sachen zeigen,
die man schnell verkehrt macht oder wo man schnell nicht mehr weiß genau,
was damit gemeint ist.
Das eine, was sie zum Beispiel lesen, in Lehrbüchern ist sowas.
Zwei Endquadrat plus drei und plus eins ist zwei Endquadrat plus Täter von N.
Und wenn man das das erste Mal sieht,
dann fragt man sich, was ist das denn jetzt?
Weil Täter von N war ja eine Laufzeitklasse, ist ja eine Menge.
Das ist eine Menge, ist die Menge aller Funktionen,
die so stark wachsen, wie die Funktionen von einem gleich N.
Das besagt ja das Okakül. So, und jetzt haben
wir hier irgendetwas, zwei Endquadrat plus eine Menge.
Das passt irgendwie nicht. Das kann man ja nicht,
man kann ja nicht eine Menge addieren in dem Sinne.
Und hiermit ist an dieser Stelle etwas anderes gemeint, was nämlich gemeint ist,
ist, dass man aus dieser Menge einen beliebigen Repräsentanten auswählen kann.
Und die Aussage ist dann wahr. Ja,
also man könnte sagen, zwei Endquadrat plus drei in plus eins,
es ist zwei Endquadrat plus F&N und FN,
F&N ist dann hier eine Funktion, die aus der Menge Tetter von N ist.
Also an dieser Stelle, wenn man das also hier so
in einer Formel hat und das Okalkül verwendet, addiert,
ist damit nicht die Menge gemeint, sondern ein Repräsentant dieser Klasse.
Okay, wir bezeichnen sowas dann auch als anonyme Funktion. Also wir kennen die Funktion nicht genau,
also hier kennen wir sie sogar, 3N plus 1,
aber häufig kennt man sie gar nicht und man sagt,
es ist irgendeine Funktion, mich interessiert auch gar nicht,
was das für eine Funktion ist.
Das Einzige, was für mich jetzt wichtig ist, ist,
dass diese Funktion vom Wachstum beschränkt ist durch Tetter von innen.
Wenn man jetzt damit rechnet, dann sieht man,
okay, klar, da kann man mit addieren,
ist ja toll, kann man ein bisschen rumaddieren,
dann könnte man Therme umwandeln in die einzelnen in die einzelnen,
mit dem Ohnkalkül abschätzen und dann kann man das irgendwie verrechnen.
Das kann man größtenteils auch tun, aber natürlich nicht in solchen parametrisierten Summen. Also wenn sie sowas haben,
Summe von Igarch 1 bis N, O von I,
also vielleicht stand da vorher I und dann sagen sie,
jeder Term ist ja O von I und dann steht das hier so und dann hätten sie sowas wie,
ja, O von 1,
plus O von 2 plus O von und so weiter.
Und dann sagen sie ja super,
der größte Term ist ja O von N und das ist ja
vom Wachstum stärker als O von N minus 1 und größer
als von N minus 2 und so weiter und dann sagen sie,
das können wir abschätzen,
Polynomregel ist O
Ja, das ist falsch. Das kann sie natürlich nicht
machen, weil sie haben ja hier envile Sumanten.
Ja, diese Summe wächst in der Länge. Deswegen geht das
nicht. Ja, sowas dürfen sie niemals tun. Das heißt,
wenn sie solche Parametrisierten Summen haben,
wenn also das N, über das sie reden,
hier quasi die Größe der Summe, die Anzahl der Sumannen bestimmt,
dann müssen sie diese Summe erst auflösen und dürfen dann das O-Kalkül anwenden.
Okay, so. Um das jetzt auf die Spitze zu treiben,
gibt es dann noch die Variante,
dass das O-Kalkül auf beiden Seiten einer Gleichung vorkommt.
Da würde also es stehen zwei Endquadrat,
plus Tetter von N ist Tetter von N Quadrat
Wenn Sie sowas sehen, ist auf der linken Seite unsere anonyme Funktion gemeint,
also irgendeine Funktion mit dem Wachstum wie eine lineare Funktion.
Und auf der rechten Seite hier ist die Klasse gemeint.
Also die Menge der Funktion, die so stark wachsen wie ein Quadrat.
So, das heißt, auf der linken Seite hier anonyme Funktion,
irgendein Repräsentant und auf der rechten Seite hier die Klasse.
Also die könnten das auch so interpretieren,
das ist ja Tetter, also obere untere Schranke.
Das heißt, für jede Funktion von N,
die in Tetter von N ist,
gibt es
eine Funktion G von
Hier ist es die ganze Menge. Hier ist es
ein Repräsentant mit konstanten C00C1 und N0, sodass C1,
Magie von N, kleiner gleich, zwei N Quadrat plus F&N.
Das F&N ist der Repräsentant für diesen Teil. Kleiner gleich
C2 Magie von N ist für alle N größer als N0. Okay, so,
das ist einfach nur nochmal, damit sie mit dieser Notation korrekt umgehen können.
Gut, ja, ich habe hier noch ein Bildchen,
um ihn so ein bisschen zu zeigen, was Wachstum dann bedeutet.
Es ist nur einfach einen kleinen Ausschnitt für X,
also es ist jetzt nicht X, sondern N,
es geht ja nur bis zehn und hier ist ein paar hundert.
Und sie sehen hier eine Reihe von Funktionen,
die vom Wachstum alle x Quadratlock x sind.
Also F und x gleich x Quadratlock x, das ist die rote Funktion. Und jetzt sehen sie,
wenn sie jetzt hier Faktoren hinzunehmen, also das sind die verschiedenen Grünfunktionen hier,
dann haben sie zehnmal oder fünfmal oder 7,5 Mal,
dann sehen sie, dass das Wachstum natürlich davon enorm beeinflusst wird,
diese Funktion wachsen natürlich, also vom Verlauf wachsen
die natürlich sehr viel stärker als diese ursprüngliche Funktion,
aber was das Wachstum der Funktion an sich angeht,
gehören die alle noch zur selben Klasse.
Das ist alles die Klasse wovon N-Quadrat Log N.
Das sind nur Konstanten, die hier entsprechend multipliziert wurden.
Hingegen die blaue Funktion ist die Funktion von X gleich X
hoch 3. Ist die hier? Und sie sehen,
die zeigt ein stärkeres Wachstum oder eine stärkere Krümmung. Und egal,
welche Konstante sie nehmen, finden sie einfach immer einen Punkt,
ab dem die blaue Funktion größere Werte liefert als die grüne Funktion.
Und das ist genau das, was das Okalkül aussagt.
Sie haben, wenn sie ihnen nach unendlich schauen,
finden sie immer einen Punkt,
ab dem die eine Funktion größer ist als die andere
Ja, okay. So, das war nochmal
ein bisschen was zum Rohkalkül aus meiner Sicht.
Und sie haben eine Frage. Soll ich Ihnen jetzt den
Übungszettel lösen? Zu welcher... Ja, Sie wollen jetzt
gerne einen Tipp hören von mir. Schauen Sie mal,
Sie finden in Stine. Finden Sie diese kleine mathematische Formelsammlung,
die ich Ihnen empfohlen habe für die Erwartungswerte.
Da können Sie mal ein bisschen weiter vorne blättern.
Da finden Sie eine Antwort auf Ihre Frage
Okay, gut. So, jetzt wollen wir es auch benutzen.
Das war alles Theorie und jetzt geht's los. So,
was müssen wir jetzt machen? Wir haben jetzt also so einen Algorithmus,
steht da im Pseudo-Code und wir wollen die Laufzeit abschätzen.
Dazu müssen wir uns für jede Operation überlegen, wie lange dauert die eigentlich?
Wir nehmen bei uns an allen Analysen an,
dass wir ein Uniformes Kostenmaß haben, das heißt,
jede Operation dauert eigentlich gleich lang.
Damit brauchen wir eigentlich nur zählen, wie viele Operationen machen wir eigentlich.
Und deswegen sieht das ja auch relativ einfach aus.
Das heißt, wenn wir irgendwelche mathematischen Operationen machen.
Wir machen Zuweisungen oder rechnen irgendwas plus, minus mal,
Diph, Mod oder so. Dann kostet das immer konstante Zeit.
Egal wie groß die Zahlen sind. Das war so O
von 1 und die, hier ist nur der Hinweis,
es gibt auch ein lugerithmisches Kostenmaß für einige Analysen.
Wir werden das hier nicht benutzen, aber es gibt es.
Und dann würde man hier die Laufzeit O von Log X
annehmen und X ist der Wert des größten Operanten.
Das gibt es auch. Also wenn man Algorithmen hat,
wo man extrem große Operanten hat, würde man das machen.
Wir machen das ja nicht. Wir gehen davon aus,
jede Operation
konstante Zeit
Dann haben wir natürlich so Blockbildungen, Klammern von Anweisungen,
das kostet auch konstante Zeit, wenn wir eine bedingte Ausführung haben,
haben wir auch konstante Zeit,
wobei man hier natürlich ein bisschen aufpassen muss,
was genau hier die Bedingung ist,
also die Auswertung der Bedingungen kann durchaus schon länger dauern,
wenn da zum Beispiel eine Funktion aufgerufen wird,
muss man natürlich gucken, wie lange braucht die Funktion,
aber das reine Ausführen der if Than Else Anweisung ist halt konstante Zeit.
Bei Schleifen ist der Augenblick, wo es das erste Mal interessant wird,
hier müssen wir die Anzahl der Schleifendurchläufe bestimmen,
also wir müssen gucken, wie häufig wir die Schleife wiederholt
und die Laufzeit ist dann proportional zu diesem Wert.
Wenn wir Funktionen haben, Dann kostet der reine Funktionsaufruf auch wieder konstante Zeit,
aber wie gesagt, wir müssen dann die Zeit addieren,
die die Funktion benötigt, um ausgeführt zu werden.
Das bedeutet, insbesondere bei rekursiven Funktionen sind wir jetzt in so einem kleinen Dilemma,
weil wir wollen die Laufzeit der Funktion bestimmen und dann kommt
ein rekursiver Aufruf der gleichen Funktion.
Dafür müssten wir jetzt ja wissen, wie lange braucht denn
diese Funktion und haben dann so eine Selbstbezüglichkeit.
Mit der werden wir uns jetzt gleich noch sehr intensiv beschäftigen,
wie man das dann entsprechend auflösen kann
So, erst mal zwei ganz einfache Beispiele.
Das erste Beispiel hatten wir schon. Wir berechnen A hoch
K. Der Algorithmus ist der hier, der heißt Exponent.
Wir haben eine Variable B, die hat am Anfang den Wert 1.
In einer Vorschleife laufen wir von 1 bis K. Und in
jedem Durchlauf der Vorschleife wird das B mit A multipliziert.
Und am Ende der Funktion geben wir dann den Wert von
B zurück. Also es ist eine einfache Möglichkeit,
um A hoch K für ganzzahlige K zu berechnen.
So, wenn wir die Aufzeit bestimmen wollen,
geben wir alle Anweisungen durch, eine Zuweisung kostet konstante Zeit.
Irgendwie wissen die Zeit nicht, irgendeine Konstante,
10-0. Dann haben wir
die Vorschleife
Die Vorschlage selber hat hier so eine Zuweisung, eine konstante Zeit.
Und dann haben wir hier entsprechend die Durchläufe. Und wir
müssen uns überlegen, wie häufig wird diese Vorschleife wiederholt.
Und ja, das sind also K-Durchläufe. Es geht von 1
bis K. Streng genommen machen wir K plus 1 Vergleiche.
Also wir prüfen ja immer, ob das Ende der Schleife erreicht ist.
Und wir machen streng genommen einen Vergleich mehr,
weil wir nämlich natürlich bei der letzten Überprüfung,
wenn wir feststellen, dass wir die Schleife verlassen müssen,
machen wir auch nochmal einen Vergleich.
Das K plus 1 vergleiche nur im Okalkül,
spielt das in der Regel dann eigentlich
keine Rolle mehr
Okay, so, dann eine Multiplikation,
konstante Zeit und hier diesen Wert zurückzugeben,
auch konstante Zeit und dann können wir die Laufzeit addieren,
also die Laufzeit für unseren Algorithmus,
bei einer Eingabe A und einer Eingabe K wäre dann also C0 plus K plus 1,
mal alles, was in dieser Schleife passiert,
also mal irgendwie C und dann haben wir noch K mal C1,
also K mal müssen wir die Multiplikation ausführen,
K plus 1 mal quasi den Vergleich,
ob die Schleife quasi beendet werden muss oder nicht und dann haben wir noch die Konstante C2 für die Rückgabe und wenn wir das anschauen,
dann sehen wir,
dass es in O von K Also ein lineares Laufzeitverhalten mit der Größe,
der mit dem Wert, mit dem Wert K aus der Eingabe.
Nur damit sie jetzt sehen, dass das keine effizienter Algorithmus ist,
zeige ich Ihnen ein anderes Beispiel zur Berechnung von A hoch
K. Das ist der folgende Algorithmus, der hier steht und
der ist schon für meinen Geschmack sehr pfiffig.
Es ist ein sehr schöner Algorithmus, um A auch K auszurechnen.
Der macht nämlich Folgendes, der hat drei Variablen,
P, Q und L und am Anfang werden die initialisiert,
P kriegt den Wert 1, Q kriegt den Wert A und L kriegt den Wert
Jetzt haben wir eine Wild-Schleife,
solange das L größer gleich 1 ist, machen wir Folgendes.
Wir prüfen, ob L. Modululo 2 gleich 1 ist,
also ob L eine ungerade Zahl ist oder nicht.
Wenn L eine ungerade Zahl ist, dann multiplizieren wir P mit Kuh.
Also P ist am Anfang 1 und QSA.
Das sieht noch so ein bisschen aus wie diese Stelle hier.
Also wenn es ungerade ist, machen wir dieses Multiplikation.
Und jetzt passiert das große Mysterium. Jetzt werden wir L
einfach durch 2 dividieren und das ist eine ganzzahlige Division hier.
Und Kuh werden wir quadrieren. Und dann machen wir den nächsten Schleifendurchlauf.
Okay, wir werden jetzt mal eben schauen, wie lange diese Algorithmus benötigt.
Das ist nämlich der einfachere Teil, aber danach,
es sei denn, sie glauben mir das jetzt alle schon so,
müssen wir erst mal gucken, dass der überhaupt AOK berechnet.
Machen wir erst mal die Laufzeit für den Algorithmus.
Das ist, wie gesagt, nicht so schwierig.
Wir haben hier drei Zuweisungen, das dauert irgendwelche konstante Zeit,
10-0. Dann haben wir diese Wildschleife und jetzt müssen wir erst mal überlegen,
also an der Wildschleife sieht man nicht so direkt,
wie viele Schleifendurchläufe die hat.
Steht also Wild L größer gleich 1 und ich frage,
wie häufig wird die jetzt durchlaufen?
Das wissen wir erst mal noch nicht.
Dazu müssen wir erst gucken,
was passiert in dem Algorithmus
Und dann kann man ja reingucken, was passiert denn mit dem L.
Also das L ist am Anfang K. Und immer,
wenn die Schleife durchlaufen wird, kommen wir zu dieser Zeile
und das L wird ganz zahlig durch zwei dividiert.
Ja, das L wird also immer halbiert. Ja,
und dann müssen wir überlegen, wie lange können wir eine Zahl halbieren,
bis wir einen Wert haben,
der kleiner gleich eins ist oder kleiner als eins ist,
weil wenn das der Fall ist,
dann ist ja die Bedingung hier nicht mehr erfüllt.
Und dann sieht man natürlich, ja, das wissen wir,
was das ist. Das ist natürlich der Logorithmus.
Das heißt, den Logorithmus des Anfangswerts von L,
das ist die Anzahl der Durchläufe, die wir haben.
Ja, und am Anfang ist das LK.
Das heißt, diese Wildschleife macht Logorithmus, du weißt,
2 von K plus 1 Durchläufe,
das Plus
Weil das ja keine ganze Zahl sein muss. Und wir müssen ja
hier die Anzahl der Durchläufe, ist ja ganz zahlig.
Also wenn das irgendwie, da brauchen wir gegebenenfalls einen Durchlauf mehr.
Okay, jetzt wissen wir die Anzahl der Schleifendurchläufe,
die anderen Operationen sind alle konstant.
Das benötigt konstante Zeit, dass das alles nur Operationen,
Rückgabe wählt auch. Wir können das ausrechnen,
dann am 10.0 plus Logorithmus dabei, 2 von K plus 1,
mal diese ganzen Konstanten plus das C4 und das ist auch von locker.
Also der Algorithmus hier oben benötigt linde Jahre Zeit,
der logorithmische Zeit
Weil sie denken, das macht nichts. Das sind
immer gerade hier zurückblättern, ja. Der eine Algorithmus hat
ein lineares Laufzeitverhalten, der wächst so. Ja,
wenn die Eingabe 10.000 eine Million ist, 10.000,
1.000, 1.1 Millionen, der andere hatte ein lugrithmisches Laufzeitverhalten,
der wächst so. Ja, das heißt,
wenn sie also die eine Millioneneingabe haben,
haben sie hier 20 Rechenschritte,
hier haben sie eine Millionen Rechenschritte und das ist ein Faktor 50.000. Ja,
also es ist signifikant schneller.
So, vorblättern
Okay, das war die Berechnung der Laufzeit,
also ein toller Algorithmus, schön schnell, ja.
Die Tatsache, dass ich hier konstanten hingeschrieben habe mit Nummern,
ist etwas, was ich nur zur Veranschaulichung hier gemacht habe,
das werden wir in Zukunft nicht mehr tun.
Also es sind irgendwie, also eigentlich müsste man ja sagen,
was ist die reale Zeit, die das wird,
da würdet ihr stehen, drei Millisekunden oder so,
aber ich will ja nicht irgendwelche Fantasiezahlen hinschreiben,
die sind ja auch nicht wichtig für uns,
deswegen stehen da einfach Cs
Okay. So, also, die Frage ist jetzt natürlich,
der Algorithmus ist schnell, aber ist er auch korrekt?
Ja, berechnet er überhaupt A hoch K?
Und um das zu sehen, bedarf es einer sehr,
sehr geschickten In-Variante, um zu zeigen, dass der Algorithmus korrekt ist.
Die In-Variante ist nicht groß, sie steht hier oben schon,
der ein oder andere hat sie wahrscheinlich schon die ganze Zeit gelesen und darüber nachgedacht.
Aber ich kann Ihnen aus eigener Erfahrung sagen,
wenn Sie mit diesem Algorithmus konfrontiert werden und man sagt ihnen,
ist der korrekt oder nicht und Sie müssen kreativ darauf kommen,
dass es diese In-Variante ist
Richtig schwieriger Schritt. Ja, wenn man sie dann sieht,
dann kann man relativ schnell auch zeigen, dass der Algorithmus korrekt ist.
Also die Invariante sagt, dass A hoch K, das ist ja das,
was wir eigentlich ausrechnen wollen, das ist die Eingabe,
ist zu jedem Zeitpunkt im Algorithmus P mal Kuh hoch L.
Das können wir uns anschauen, zu Beginn das Album an dieser Stelle hier,
da sehen wir P ist gleich 1,
Kuh ist gleich A, L ist gleich K,
wenn wir das jetzt hier einsetzen, P ist gleich 1,
da steht hier einmal Kuh ist A,
einmal A, L ist K,
also einmal A hoch K,
also A auch K gleich einmal auch K. Also offensichtlich ist
die Invariante am Anfang korrekt
Das ist natürlich der einfachere Teil gewesen. Jetzt bearbeiten wir
die Schleife und machen einen Schleifendurchlauf nach dem nächsten.
Und dabei verändern sich PQ&L. Und wir behaupten, dass zu jedem Zeitpunkt,
also immer nach einem vollständigen Durchlauf der Schleife, muss man sagen,
wieder gilt, dass AOK gleich P-Malku hochell ist.
Das machen wir gleich auf der nächsten Folie, aber an dieser Stelle schon mal,
warum liefert uns das am Ende das korrekte Ergebnis?
Also warum ist das eine gute Innenvariante? Wenn Sie diese Schleife durchlaufen und durchlaufen,
durchlaufen, dann wird irgendwann das L kleiner gleich,
also die Bedingung nicht mehr erfüllen und Alice Guns hat,
das heißt, das L wird null sein.
Also wenn die Wildsteife beendet, ist es L-0.
Und wenn sie hier das L auf null setzen,
dann steht hier A auch, K ist gleich P,
mal Q hoch null und Kuch 0 ist 1. Egal,
was das Kuch ist, Kuch 0 ist immer eins und
dann steht hier A auch K gleich P und P ist unser Rückgabe wert.
Und damit hätten wir gezeigt, dass dieser Algorithmus tatsächlich
das korrekte Ergebnis berechnet. Jetzt müssen wir noch zeigen,
dass in jedem Schleifendurchlauf tatsächlich diese Bedingungen hier gilt
Das machen wir jetzt, ja. Also, Schleifen in Variante,
auch Kargleich, P, Maku hoch L. Vor dem,
vor der Schleife, gilt P gleich 1, Kuhgleich A,
L, Gleich K, also A auch K,
gleich P, Maku hoch L.
Das ist die Invariante, ist also korrekt. Nach einem Schleifendurchlauf
wollen wir zeigen, dass diese Invariante wieder gilt. Wir wissen,
dass vor dem Schleifendurchlauf die Innenvariante gilt, also vor Zeile 3,
das ist also da, wo die Schleife beginnt,
gilt die in Variante und jetzt rechnen wir und danach muss sie wieder gelten.
Während wir rechnen,
verändern wir PQ und L und wir müssen einfach nur gucken,
was passiert denn mit PQ und
Dazu müssen wir eine Fallunterscheidung machen, denn wir haben hier
so ein If-Statement. Es passiert ja was anderes,
zumindest mit der Variablen P, wenn L gerade oder ungerade ist.
Streng genommen passiert auch was anderes mit L,
wenn L gerade oder ungerade ist, weil die ganzzahlige Division hier,
ja, ist ja mathematisch ein bisschen was anderes.
Also einmal geht es auf und einmal haben wir den Rest. Okay,
so, also was passiert, wenn L gerade ist,
das ist der erste Fall, dann ist L-Modulo 2 gleich null.
Jetzt müssen wir so ein bisschen die Ls und Kuhs unterscheiden,
die vorher und nachher gelten. Wir sagen jetzt mal L und Kuh,
nachher am Ende des Schleifendurchlaufs ist das L und Q,
das ist der Zeitpunkt, den wir uns anschauen und die Werte,
die das vorher hatte am Anfang des Schleifendurchlaufs,
das seien mal L-Strich- und Kuhstrich.
Also damit wir die beiden unterscheiden können. So,
dann wissen wir, AOK ist P mal Kuhstrich-Hochel-Strich.
Das ist nämlich nur die Innenvariante, die vor dem Schleifendurchlauf galt.
Das P haben wir nicht verändert, gucken wir rein.
Also das P ändert sich nicht, weil das war ja gerade,
das heißt, diese Zeile haben wir nicht ausgeführt und das P wird nicht verändert.
Also das bleibt gleich. Nur L und Kuh ändern sich. So,
was passiert, ist aus dem,
wir können das hier umformen, das ist also P,
mal Kuhstrich-Hochel, das gleiche wie P, mal Draht.
Hochelstrich halbe. Kommt das Gleiche raus. Haben also nur das
eine quadriert und das andere halbiert. Und weil das L,
sprich ja eine gerade Zahl ist, L ist gerade,
ist also Kuhstrich, Quadrat ist das Gleiche wie Kuh,
weil wir das Kuh ja quadrieren im Algorithmus.
Und das L-Strich halbe ist das Gleiche wie das L,
weil wir das L ja durch zwei dividieren.
Damit gilt die Innenvariante auch Nachdurchführung dieser Schleife.
So, jetzt haben wir noch den zweiten Fall.
Der zweite Fall ist Alice Ungrade. Das heißt,
L-Modulu 2 ist gleich 1 und wir führen diesen bedingten Teil
hier aus, den Teil, den füllen wir aus.
Das heißt, das P verändern wir jetzt. Okay,
dann wissen wir, naja, am Anfang ist A
auch K gleich P-Strich, mal Kuhstrich, hoch L-Strich.
Das sind die Werte, die wir vor Schleifendurchlauf haben.
Jetzt läuft die Schleife durch, wir verändern PQ und L. Was wir machen können,
ist, wir können das hier umformen, wir sagen,
okay, wir ziehen mir mal einen Kuhstrich aus dem Produkt heraus,
dann hätten wir P-Strich, mal Kuhstrich, mal Kuhstrich hoch L-Strich,
minus 1. Wer eins rausgenommen, damit das L,
das L, wird das halt gerade,
weil es war vorher ungrad,
jetzt haben wir elfstrich minus 1
ist gerade
Dann können wir wieder den Trick machen von dir oben.
Wir dividieren das durch zwei und das quadrieren wir.
Und dann sehen wir, aha, also Kuhstrich wird quadriert.
Das ist das neue Kuh. Und hier haben wir L-Strich minus eins halbe,
weil das L-Strich ungerade ist, ist das das neue L.
Also hier steht P-Strich mal Kuhstrich, mal Kuh hoch L.
Und was ist P-Strich mal Kuhstrich? Da gucken wir in
diese IF-Zeile rein. Da sehen wir P-Strich mal Kuhstrich,
ist das neue P. Ja,
also wir multiplizieren das alte P mit Kuh und kriegen den
entsprechenden Wert heraus.
P-Malkuch, ey
Da wird das mal gezeigt, die Innenvariante gilt.
Und dann wissen wir, am Ende des Algorithmus ist Elgarch Null,
auch KSP mal Kuch L,
das heißt auch KSP und das ist das Ergebnis.
Diesen Beweis habe ich hier mal eingeschoben, um ihn zu zeigen,
wie mit diesen Innenvarianten Laufzeitbeweise geführt werden.
Das werden wir ab und zu machen in der Vorlesung,
nicht so häufig. Und ich kann Ihnen auch schon verraten,
dass das ein sehr schwieriges Beispiel ist.
Also ich persönlich finde das schwer, dann nachzuvollziehen, warum es so ist.
Also wenn man es erstmal aufgeschrieben sieht, dann geht es.
Aber wenn man sich vorstellt,
selber diesen Beweis zu entwickeln, ist es echt
ein schweres Beispiel
Okay, aber eigentlich wollten wir ja auch mehr über Laufzeiten reden.
Deswegen gucken wir mal weiter in Richtung Laufzeiten. Das eine
Problem, was wir noch haben, ist die Rekursion.
Also wie wollen wir mit der Situation umgeben,
dass eine Funktion sich selber aufruft? Dafür gibt es in
der Mathematik ein Modell und das sind sogenannte Rekurrenzgleichung.
Da macht man das Gleiche, was wir in der Informatik
machen mit der Rekursion, macht man mit Funktion.
Und dann sieht das so aus. Man hat zum Beispiel
eine Funktion und die definiert man auch rekursiv. Man sagt dann,
TVN ist gleich konstant, wenn das N klein ist,
N gleich 1 oder ist es TVN minus 1 plus C1,
wenn das N größer ist
als eins
Okay, oder ein anderes Beispiel ist Tee von Ennis konstant,
für Engleich 1, ODT von Ende ist gleich zweimal Tee von N halbe plus C.
Wenn das N größer ist als eins. Hier bilden wir
jetzt die Rekursion eins zu eins auf die Laufzeitfunktionen ab.
Die Laufzeitfunktion hat die gleiche Eigenschaft wie unser Algorithmus,
dass sie sich selber wieder aufruft,
zur Definition von Tee von N verwenden wir das T von N hier.
Unser Ziel ist es jetzt,
ausgehend von so einer Beschreibung der Funktion eine Formel zu finden,
die das T von N angibt, und zwar ohne,
dass das TVN auf der rechten Seite nochmal vorkommt.
Das ist unsere Aufgabe, wenn wir das geschafft haben,
haben wir auch die Laufzeit beschrieben
Okay, das müssen wir machen und das braucht man in der Tat
auch sehr häufig. Für uns gilt im Allgemeinen immer,
das gilt für die Mathematiker nicht unbedingt,
aber für uns als Informatiker, dass wir da mit Laufzeiten beschreiben,
das ist TV und Ende ist also typischerweise für nur natürliche Zahlen definiert.
Wir haben also keine negativen Zahlen, wir haben auch normalerweise dort
keine reellwertigen Zahlen oder so, also nur natürliche Zahlen.
Wir wissen, dass für all unsere Gleichung dieser Form alle Rekurrenzgleichung,
die wir sehen, ist die Laufzeit für kleine N immer konstant.
Also wenn das nur klein genug ist, ist es
immer konstant.
Das hängt mit dem O-Kalkül zusammen, weil wir wissen,
für kleine N, können wir das Ganze immer durch eine Konstante abschätzen.
Okay, mit Auf- und Abrundung werden wir
auch einigermaßen entspannt umgehen und einfach immer ein bisschen aufrunden.
Das stört uns dann nicht so sehr,
weil wir wollen auch nur eine Laufzeitschranke berechnen. Okay,
unser Ziel ist also jetzt eine asymptotische Laufzeit für Tee zu bestimmen und
wir brauchen eine geschlossene Formel für das T von N. Okay,
als Beste, was man erstmal machen kann, ist rumprobieren.
Das heißt, wir setzen einfach die Funktion da mal ein
und gucken,
was passiert
Wir haben also TVN, ist T von N minus 1 plus C1.
Das ist die Definition. Und jetzt wissen wir,
T von N minus 1 ist ja TVN N minus 2 plus C1.
Und das ist das Gleiche wie TVN N minus 3 plus C1 plus C1 plus C1.
Und T von N minus 4 plus C1 plus C1
plus C1 plus C1. Und jetzt können Sie wahrscheinlich überlegen,
jetzt können Sie dann überlegen, wie geht denn das jetzt so weiter?
Und dann kommt N minus 5, N minus 6.
Und irgendwann kommen wir ja mal zu dem Punkt,
dass das hier konstant wird. Und das passiert genau dann,
wenn der hintere Teil hier in minus 1 groß ist.
Also wir machen das immer so weiter.
Und dann würde hier stehen TVN
Minus N minus 1. Und dann haben wir das Ganze N minus 1
mal gemacht und jedes Mal haben wir sonst C1 addiert.
Das heißt, hier steht plus C1,
plus C1 und so weiter, N minus 1 mal.
Okay, das N minus 1 ist das Gleiche wie eins.
Also hier steht T von 1 plus N minus 1
mal C1. Ja, und da können wir das einsetzen.
Das ist die Konstante, C00. Und dann sehen wir,
das ist O von N. Also das heißt,
eine Funktion, die sich so verhält,
hat das Wachstum O von N. Okay,
das war offensichtlich ein ganz, ganz einfaches Beispiel.
Wir machen ein Beispiel,
was ein klein bisschen schwieriger ist
Wir schauen uns an TVN gleich zweimal C von N halbe plus C.
Der Trick ist genau der gleiche. Wir nennen das übrigens
Substitutionsmethode. Wir kennen die Regeln nicht,
wir setzen einfach die Funktion ein,
immer mal wieder und gucken dann,
wie die Funktion sich entwickelt und versuchen dann eine geschlossene Formel zu finden.
Also wir sehen TVNNS 2 mal TVNN halbe plus C.
Jetzt müssen wir für TVN halbe hier was einsetzen und
zwar setzen wir die Definition wieder ein,
denn TVN halbe wäre zweimal Tee von N Viertel plus
Ja, setzen wir also hier jetzt ein und dann haben wir diese Formel,
das können wir jetzt ein bisschen zusammenfassen und dann steht da viermal Tee von N Viertel plus zweimal C plus C. Okay,
das kann man jetzt noch ein paar Schritte machen und wenn sie das da machen,
dann sehen sie das, wenn sie das E-Mail gemacht haben,
dann wird der Faktor hier vorne immer mit zwei multipliziert,
also steht hier zwei hoch E und der Quotient hier,
der wird immer durch zwei dividiert,
dass hier steht auch zwei UI, also zwei UI,
mal T von N durch zwei UI.
Und hier hinten haben sie wieder so eine Summe,
die immer länger wird, aber die haben diesmal Faktoren, diese Sumanten.
Und zwar sehen sie, hier haben sie einen C,
dann haben sie einen 2C, dann hätten sie einen 4,
10, 8C und so weiter.
Und die Summe muss ich dann im Allgemeinen so aus,
dass sie hier zwei UI minus eins,
mal zehn Jahren plus zwei UI minus zweimal C und so weiter bis C. Okay,
darauf machen wir erstmal eine Formel mit einer Summe drin.
Das heißt, hier ist das Gleiche, was wir eben hatten.
Und das ist gleich zwei hoch i mal T von N
durch zwei UI, das hatten wir schon.
Plus, und hier haben wir jetzt die Summe,
die geht von K gleich 0 bis i minus 1,
2 UK mal
So, bis dahin sind wir gekommen,
wir haben es jetzt auch nicht so richtig gelöst, unser Problem,
mir steht ja immer noch die Funktion Tee auf der rechten Seite,
aber wir sehen, wie dieser Parameter hier immer kleiner wird,
also mit jedem I, was größer,
was es größer wird, also was I wächst,
wird das N durch zwei UI natürlich kleiner.
Und das nächste, was wir jetzt machen müssen,
ist, wir müssen herausfinden,
nach wie vielen Schritten dieser Teil hier konstant wird,
wo wir da eine Eins einsetzen können.
Und dann ist das, naja, das N durch zwei UI,
was hier drinsteht, das muss kleiner gleich eins werden,
weil dann bricht die Rekussion ab
wir können die Konstante einsetzen. Und wenn N durch zwei UI,
kleiner gleich eins ist, dann ist es natürlich genau dann
der Fall, wenn N-Kleiner gleich zwei UI ist.
Also wir holen das zwar auch eh auf die andere Seite und das ist dann der Fall,
wenn I größer gleich der Lugrithmus zur Basis 2 von N ist.
Okay, jetzt wissen wir, wie viele Schleifendurchläufe oder wie
viele rekusive Aufrufe unsere Funktion machen wird,
bevor sie am Rekursionsende angekommen ist.
Das setzen wir einfach ein. Also wir setzen jetzt
das I auf Lugrithmus zur Basis 2 von N
und dann ist das T von N gleich zwei UI mal
T von N durch zwei UI plus C mal diese Summe.
Also das ist das Gleiche wie hier,
nochmal abgeschrieben
Und jetzt setzen wir das ein und das ist jetzt
kleiner gleich, weil es dir das Skript ausgedruckt haben.
Da steht bei Ihnen noch ein Gleich an dieser Stelle.
Es ist streng genommen kleiner gleich. Es ist nicht wirklich ganz wichtig,
aber ich habe mich heute daran erinnert,
dass das letztes Mal jemand verwirrt hat, extrem,
weil das I natürlich nicht, also das Ende ist nicht immer eine Zweier-Potenz.
Deswegen ist das hier eigentlich auch gerundet. Also das kleiner
gleich, zwei Hochlogorithmus zur Basis 2 von N. Mal.
Und dann haben wir Tee von 1,
weil der Teil jetzt kleiner geworden ist als eins,
hier von 1 plus, Konstante, mal,
jetzt haben wir hier die Summe, K,
gleich 0 bis Logorithmus zur Basis 2 von N,
minus 1,
2 UK
Okay, so, jetzt haben wir es fast geschafft,
weil das T1 können wir durch die Konstante ersetzen und
jetzt haben wir auf der rechten Seite kein Tee mehr.
Das ist unser Ziel. Wir müssen also diese Abhängigkeit von
sich selber in der Definition aufklären, auflösen. Okay,
jetzt müssen wir aber noch diese Summe hier ausrechnen und das ist zum Glück eine Summe,
die die Informatiker und die Mathematiker ziemlich gut kennen.
Das ist eine exponentielle oder auch eine geometrische Reihe.
Namen funktionieren beide und dafür gibt es eine geschlossene Formel,
denn die Summe von K gleich 0 bis N X
hoch K ist X hoch N plus 1,
minus 1 durch X minus
Für alle X ungleich eins, nicht null, was die hier stehen.
Also wenn da nämlich, wenn das X gleich eins ist,
ist ja der Nenner hier nicht definiert.
Also für alle X Ungleich eins ist das der Fall.
Okay, so, das können wir hier einsetzen,
das benutzen wir hier einfach. Und dann sehen wir sofort,
das X ist ja in unserem Fall zwei, zwei minus eins ist eins,
das ist der Nenner, fällt hier gleich weg.
Und hier oben haben wir zwei hoch, ja das K, nee,
das ist das Andy, das ist Logorithmus zu weit,
zwei von N minus eins, können wir einsetzen.
Und wenn wir das machen, dann haben wir hier N.
Zwei Hochlogorithmus, zuweise zwei von NSN. N mal T1 ist eine Konstante,
C plus zehnmal und diese Summe hier ist Logorithmus zur Basis 2 von N.
Ja, das ist minus eins,
hebt sich mit dem Plus eins auf, minus eins,
das ist dieses minus eins.
Und das würde jetzt geteilt durch zwei minus eins, ja eins. Okay,
das ist auch N und dann haben wir N mal C
plus zehnmal N minus C, also zweimal zehnmal N-C ist O von N.
Also wir wissen, auch dieser Algorithmus hat ein lineares Laufzeitverhalten.
Das ist die Art und Weise,
wie man Rekursionen durch Rekurrenzen beschreibt und die Rekurrenz dann auflöst.
Formal haben wir noch nicht gezeigt, dass das stimmt.
Ja, das ist mathematischen Sinn, noch kein vollständiger Nachweis,
dass das auch gültig ist, weil wir haben da immer Abschätzungen gemacht und so weiter.
Das ist nur die Herleitung, wie wir darauf gekommen sind.
Okay, jetzt brauchen wir einen Beweis durch eine vollständige Induktion,
die werde ich Ihnen jetzt auch zeigen.
Aber hier ist es auch so, dass wir im Laufe der Vorlesung,
wo wir sowas ab und zu nochmal machen müssen,
eigentlich unserer Intuition dann erstmal glauben.
Also wenn wir die Herleitung so gemacht haben,
werden wir nicht jedes Mal einen Induktionsbeweis machen.
Das ist einfach der Vollständigkeit halber,
dass Sie hier einmal gesehen haben,
dass man da streng genommen machen muss
Okay, Induktionsbeweis, der ist eigentlich ganz einfach.
Und wenn man den dann anwendet, dann kriegt man plötzlich
ein ganz unerwartetes Problem. Also sie würden sagen,
okay, also wir wollen ja zeigen,
Tee von NSO von N und dann nehmen wir jetzt eine konstante K,
ist das jetzt bei mir,
also TV und N soll irgendwie kleiner gleich K mal in sein.
Dann wäre ja das Wachstum linear. Das wollen sie zeigen
. Und dann sagen sie, super,
das ist meine Annahme und dann haben wir einen Induktionsanfang für Tee von 1. Wissen wir,
das ist eine Konstante und das ist kleiner gleich K mal eins,
wenn das K irgendwie größer gleich zäh ist.
Können wir ja so wählen, also ist okay.
Können das K ja ein bisschen größer machen als C,
wäre also alles gut
Gut, jetzt kommt der Induktionsschritt. Dann sagen wir TV
N ist zweimal von zweimal Tee von N halbe plus C
und Tee von Ennen halbe ist ja kleiner als das TV N.
Wir setzen also in der Rekussion quasi die Induktionsannahme ein.
Und dann würden wir reinschreiben, das ist kleiner gleich zweimal
Karma in halbe. Karma Lentee von N halbe,
wäre kleiner, wäre ich Karma in halbe plus C.
Und das ist Karma N plus C.
Das funktioniert nicht
Ja, weil wir wollten ja zeigen,
dass das Tee von Endkleiner gleich k mal N ist.
Und jetzt haben wir gezeigt, dass Tee von Endkleiner gleich
k mal N plus C. Das ist so blöd, ne?
Das können wir jetzt nicht abschätzen. Ist ja plus 10 nicht minus 10. Das,
was man intuitiv an dieser Stelle denkt, ist, ah,
okay, klar, die Schranke ist irgendwie zu klein.
Vielleicht muss das 2K sein oder 2K plus C.
Wir haben die irgendwie zu klein gemacht. Und deswegen kommt
das hier nicht hin. Dieser intuitive Gedanke ist falsch.
In der Regel haben sie in diesem Situation die Schranke zu groß gemacht.
Ja, weil in dem Induktionsbeweis setzen sie die Annahme ja
hier ein
Wenn Sie die Schranke kleiner machen, dann geht es plötzlich.
Also, wenn wir mal sagen, TV Ende ist kleiner,
gleich Karma in Minus-C. Jetzt machen wir die Schranke kleiner.
Dann können wir das Gleiche nochmal machen für Tee von 1
, haben wir eine konstante C.
Das muss kleiner, gleich Karma 1 minus C sein.
Und das ist jetzt wahr für K größer, gleich zweimal C.
Okay, müssen die Konstante ein bisschen größer wählen.
Der Induktionsschritt ist C von N gleich zweimal Tee von N
halbe, plus C, kleiner gleich, zweimal.
Jetzt setzen wir das ein, ne?
TV N halbe ist Karma in halbe, minus C,
plus C. Und das ist kleiner,
gleich Karma
Und das ist genau der Therm, den wir haben wollten.
Okay, also hier nur für dieses einfache Beispiel,
mal einmal gezeigt, dass man eigentlich so einen Induktionsbeweis führen muss.
Wie gesagt, wir werden das in der Regel hier nicht tun.
Gut. Ja, in der Regel ist es auch so,
dass unsere Rekurrenzgleichung, die wir haben,
nicht so simpel sind wie die,
die wir gerade gesehen haben.
Die, die man in Algorithmen hat,
sind natürlich häufig schon schwieriger.
Eine Frage
Weil wir hier zweimal C haben, also minus 2C und hier
haben wir nochmal Plus C. Bleibt ein minus C über.
Nee. Also Tee von in halbe ist K,
also K mal in halbe minus C. Okay. Hier,
und da steht eine 2 davor,
also multiplizieren wir das mit 2,
da haben wir zweimal K mal N,
minus 2C,
plus C,
minus 2C plus C
ist minus
Hier? Nee, wir haben das TVN definiert,
also als Kleiner gleich K mal N-C. Das ist C,
ist unabhängig von dem K. Ja, ist einfach,
wir hätten hier auch K mal N minus 2C schreiben können,
weil sie wollen, dann wäre es ein bisschen anders gelaufen,
wäre auch gegangen.
Aber wahrscheinlich, wahrscheinlich auch gegangen. Ja, okay.
Gut, also normalerweise haben wir schwierigere Gleichungen.
Deswegen brauchen wir noch so Tricks. Ich zeige Ihnen
noch mal ein paar Tricks,
um das aufzuklären
Hier ist ein ganz toller. Nur damit sie ihn
mal gesehen haben, den werden wir auch nicht benutzen.
So kompliziert werden unsere Funktion jetzt noch nicht. Wenn sie
mal im Masterstudium sind, dann schon. Mal angenommen,
sie hätten sowas wie TVN gleich zweimal Tee von nach unten abgerundet.
Wurzel von N plus Login. Und dann,
das ist schon ein ziemlicher Horror hier und haben sie dann
verhält sich das hier mit einer Wurzel, wird das immer kleiner.
Und wenn sie das jetzt einsetzen, dann sählen sie schon,
das wird nicht so einfach. Es gibt aber die Möglichkeit,
eine Substitution zu machen. Sie können sich überlegen,
ob sie die Funktionen nicht umwandeln Substitutionen,
die man hier machen muss, ist, dass man sagt,
wir setzen mal M gleich Log-in oder N gleich 2 hoch M.
Das wäre das Gleiche. Und wenn man das mal hier einsetzt,
dann hätte man, würde man hier sagen, okay,
das ist hier TVNN ist zweimal Tee von Wurzel, zwei hoch Log-in,
das ist das gleiche WN, zwei hoch Log-in, plus Log-in.
Und das ist das Gleiche wie dann Tee von zweimal M.
Zwei hoch M, Entschuldigung, zwei hoch M ist das gleiche WN.
Und das ist zwei Hochtee von zwei hoch M halbe plus M.
Und wenn wir jetzt eine neue Funktion nehmen,
die nennen wir S von M, vielleicht Tee von zwei UM,
Dann steht hier S von M gleich zweimal S von M halbe plus M.
Und die kennen wir schon fast nicht ganz.
Wenn man die dann auflöst, kommt der M-Log-N rauf,
M-Log-M raus und dann muss man das M wieder rücksubstituieren.
Und dann steht da TVN gleich, oh von Log-N,
Log-Log-In. Ich sehe schon, es wird lauter.
Das ist ein heftiger Trick, ja.
Und das muss genau passen, dass man sowas anwenden kann.
Wir haben kein Beispiel in der Vorlesung, wo wir es brauchen.
Ja, also hier nicht. Das brauchen wir aber.
Jetzt müssen sie wieder ruhig sagen. Das wird, das braucht man. Also,
Manchmal kommt man mit diesem Einsetzen nicht weiter und dann hilft es einfach mal,
sich zu überlegen, wie der Algorithmus sich selber aufruft.
Und wie viel Zeit er dabei verbraucht. Und wir haben,
wir wissen, wir starten den Algorithmus und dann hat er eine Laufzeit,
also die ist unsere Rekurrenz, TVN gleich dreimal TVN, Viertel plus CN-Quadrat.
Wenn wir das hätten, dann wüssten wir,
wir starten die Funktion und die hat im ersten Funktionsaufruf,
hat die C von Endquadrat viel Laufzeitbedarf und die rekursiven Aufrufe.
Und davon gibt es drei Stück, drei rekursive Aufrufe,
eins, zwei, drei, wir malen das jetzt als so ein Baum.
Und jetzt überlegen wir uns, wie viel Laufzeit brauchen denn
diese rekursiven Aufrufe
Und dann sehen wir, naja, das N,
das wird ja durch vier dividiert, also N, Viertel.
Und hier hätten wir dann zehnmal ein Viertel zum Quadrat,
also eigentlich erzählt von Endquadrat,
aber das N hat sich ja jetzt schon verkleinert auf ein Viertel.
Zehnmal ein Viertel zum Quadrat, hier auch, hier auch.
Jetzt wissen wir, dass in der Funktion,
die Funktion wieder aufgerufen wird, dreimal,
ja, und das N wird wieder durch vier dividiert.
Das heißt, hier haben wir zehnmal N-16tel Quadrat, an allen Aufrufen.
Was bei solchen Rekursionsbäumen passiert, ist, dass der Laufzeitbedarf,
den sie für jede Ebene haben, immer Gleiches.
Also sie sind, hier steht CN-Quadrat. Hier steht überall CN-Viertel-Quadrat.
Hier steht überall C, mal N-16tel-Quadrat bei allen Werten.
Und da geht das immer so weiter.
Und irgendwann steht hier überall eine Konstante. So,
das heißt, innerhalb dieser Zeilen können sie die Summe bestimmen,
indem sie einfach sagen, okay, wie viel sind das denn?
Das werden ja von mal zu mal immer dreimal mehr.
Es ist 1, 3, 9, 27 und so weiter.
Also immer ein Faktor 3 mehr. Und dann können sie
das addieren. Und dann sehen sie, okay,
das ist hier dann offensichtlich dreimal 16 CN-Quadrat.
Und das sind hier 3, 16tel zum Quadrat,
mal CN-Quadrat und so weiter
Und hier hätten wir ganz häufig das T1. Dann müssen Sie sich überlegen,
wie viele rekusive Aufrufe brauchen Sie, um die ganze Berechnung durchzuführen?
Also wie tief ist dieser Aufrufsbaum? Und dann sehen Sie,
naja, Sie dividieren immer durch vier, das können Sie genau,
Logorithmus zur Basis vier von N mal machen.
Dann ist Schluss. Ja, dann ist der Wert kleiner
gleicher Eins. Okay, und dann können Sie sich überlegen,
wie viele Aufrufe gibt es hier?
Und das sind N-Hoch-Logorithmus zur Basis vier von drei.
Das ist eine ganz komische Zahl. Das Beispiel ist auch im Kormen,
wenn Sie das da lesen, finden Sie keine Erklärung,
warum das so ist.
Der Hinweis, der steht hier unten
Was sie eigentlich stehen müsste, wäre drei hoch.
Logorithmus zur Basis wie von Ende. Das versteht man.
Also wir wissen von Ebene zur Ebene geht es immer mal drei.
Und wir haben Logorithmus zur Basis 4 von N viele Ebenen.
Also drei hoch Logorithmus war es für von N. So,
und jetzt gibt es ein paar Logorithmenregeln, die zeigen,
dass drei Hochlogorithmus zur Basis 4 von N das Gleiche ist,
wie N-Hochlogorithmus zur Basis 4 von 3. Tja,
das muss man wissen im Leben.
Wenn man das weiß, dann versteht man auch,
warum das hier unten steht.
Und dann kann man
das gut nachvollziehen
Okay, so, diesen Baum können wir jetzt also in eine Formel umwandeln.
Und dann sehen wir, also hier nochmal die Rekurrenzgleichung,
T von NS3 mal T von N Viertel plus CN-Quadrat.
Und dann sehen wir hier, das ist gleich CN-Quadrat plus 3,
Sechzehntel CN-Quadrat. Das sind jetzt die Ebenen in dem Baum.
Plus 3, Sechzehntel Quadrat, CN Quadrat und so weiter.
Dafür schreiben wir die Zoom-Formel hin. Also,
das ist die Summe von I gleich 0 bis Logorithmus,
so war es hier von N minus 1. 3,
Sechzehntel Luch ihm als CN-Quadrat, also diese Summe.
Plus den ganzen Rest hier. Das sind die
konstanten Aufrufe hinten
Die Summe schätzen wir ganz großzügig ab, bis unendlich. Ja,
das ist hier nicht so schlimm,
weil dieser Faktor hier, das ist ja ein Bruch,
der ist kleiner als eins und dann geht die Funktion eh gegen eine konstante,
ist egal wie viele, so man sie hier noch brauchen,
das ist die unendliche geometrische Reihe übrigens,
K gleich 0 bis unendlich, x hoch K,
das geht durch eins, also geht gegen eins,
durch eins minus x, aber nur,
wenn das x vom Betrag kleiner ist als eins,
weil sonst wächst das natürlich gegen unendlich,
das muss schon kleiner sein als eins.
Ja, und das können wir dann da reinschätzen,
dann haben wir eins durch eins, minus 3,
16., CN-Quadrat plus Täter von dem und Und da der
Logorithmus so war als 4 von 3 kleiner ist als N-Quadrat,
also als das Quadrat hier, ist das O von N-Quadrat.
Das ist die Rekursionsbaummethode. Man überlegt sich also wirklich in einem Baum,
welche rekursiven Aufrufe macht der Algorithmus und schätzt die Laufzeit dann
Ebene für Ebene ab und kann das dann entsprechend addieren.
Okay. So, nachdem sie das jetzt alles verstanden haben
und selber anwenden können, kommt das Erleichternde, ah,
denn für ungefähr 95 Prozent der Fälle kann man eine allgemeine Formel angeben und kennt dann das Ergebnis.
Ja, das nennen wir das Mastertheorie,
es löst sozusagen die allgemeine Rekurrenz, die hier oben steht.
TVN ist gleich eine Konstante, wir werden gleich eins oder
A mal T von N durch B plus irgendeine Funktion F&N.
Das hier ist die häufigste Rekurrenz, die wir sehen in der Informatik.
Warum sehen wir die so häufig? Naja,
in der Regel wird ihre Funktion ein paar Mal aufgerufen,
rekursiv, einmal, zweimal, zehnmal,
also A mal aufgerufen und in dem rekursiven Aufruf verkleinern sie in der Regel die Eingabe,
um irgendeinen Faktor.
Das passiert fast in allen Fällen, wo man Algorithmen entwirft.
Das ist gerade dieser Faktor 1 durch B. Also A mal
C von Endo durch B plus F&N.
Und F&N ist die Funktion, die Laufzeitfunktion ihres Algorithmus.
Da haben sie irgendwie was. So, wenn das so ist,
also wenn ihre Rekurrenz so aussieht, dann können sie direkt sagen,
welche Laufzeitklasse das Ganze hat.
Dazu muss man allerdings drei Fälle unterscheiden. Das heißt,
man muss sich gucken, wie A im Verhältnis zu B
eigentlich steht
Und hier sind die drei Fälle. Also man schaut sich an,
was ist der Lugerithmus von Art,
der Lugrithmus zur Basis W von A und guckt sich an,
wie viel Zeit braucht die Funktion hier selber, das F&N.
Wenn das F&N in O von N-Hochlogorithmus zur BSB von A minus Y,
also irgendwie ein kleines bisschen müssen sie noch abziehen, ist,
dann ist die Laufzeit in Tetter von N-Hochlogorithmus zur BSB von A.
Wenn das gleich ist, also wenn die Funktion F&N vom
Wachstum genauso ist wie N-Hochlogorithmus zur BSB von A,
dann ist es Tetter von Ellenhochlogorithmus zum Beispiel von A,
Malogerithmus von
Ja. Und wenn das F&N stärker wächst als das,
also hier ist jetzt ein Omega,
dann ist das C von Engleich Tetter von F&N.
Das heißt, dann wird die Laufzeit nur durch das F&N
bestimmt und der rekrusive Teil spielt keine Rolle.
Sieht immer noch kompliziert aus, aber sie dürfen nicht vergessen,
dass A und B sind ja konkrete Zahlen.
Das ist irgendwie zwei und zwei oder zwei und vier oder irgendwie sowas.
Und wenn sie das dann hier einsetzen, den Logorithmus ausrechnen,
dann ist es relativ leicht, das hier zu überprüfen.
Hier gibt es noch eine Zusatzbedingung, die gelten muss,
die muss man dann auch noch überprüfen für den dritten Fall.
Wenn die dann nicht stimmt, dann hat man ein Problem,
aber das passiert nicht so häufig
Okay, so, ein Beispiel, wir hatten ja schon
diese Funktion, TVN gleich C oder zweimal TVN halbe plus C.
Was muss man jetzt machen? Okay,
das A ist offensichtlich zwei, das B ist offensichtlich auch zwei,
die Funktion F von Ende ist eine konstante, von Enlecht See.
Um das Mastertheorium zu benutzen, müssen wir als erstes prüfen,
welchen der drei Fälle müssen wir anwenden.
Dazu brechen wir als erstes mal den Logorithmus zur Basis
B von A, weil das kommt ja hier überall vor.
Das rechnen wir aus, bei uns ist B und A
beides zwei, das heißt der Logorithmus von 2 zu Basis
2 ist
Okay, jetzt gucken wir,
also wie ist denn unsere Funktion F von N im Verhältnis zu N
hoch 1 minus irgendeinen kleinen Y oder wie verhält es sich
zu dem Täter von N hoch 1, also zu N.
Also das schauen wir uns an. So,
die Funktion selber ist eine Konstante und eine Konstante hat ja
kein Wachstum, die ist einfach so.
Und deswegen wächst die geringer als O von N
hoch 1 minus irgendetwas klein bisschen irgendeine kleine Konstante.
Und deswegen müssen wir der erste Fall des Mastertheoriums greift und
das Tee von N ist Täter von N Hochlorhythmus
zu Weiß B von A und das
ist Täter von
Ja. Okay, das wäre jetzt also die Anwendung.
Wenn wir jetzt mal angenommen,
hier würde zweimal Tee von N halbe plus N stehen.
Ja, könnte ja auch sein. Also wenn wir sowas
hätten wie Tee von N gleich, sehen Sie das?
Soll ich hier hingehen? Also,
wenn wir sowas hätten wie zweimal Tee von N halbe plus,
meinetwegen zehnmal
Ja? Nur mal, um ein anderes Beispiel zu sehen.
Dann gilt dir vorne erstmal noch das Gleiche. A ist 2B,
ist gleich 2 und damit wäre der Logarithmus zur Basis
B von A immer noch eins. Das hätte sich jetzt
nicht geändert. Das ist noch das Gleiche.
Aber die Funktion ist jetzt anders. Also unsere Funktion F&N
ist jetzt zehnmal N. Ja, jetzt müssen wir gucken,
wie verhält sich C mal N zu unserer Funktion,
die im O-Kalkül hier vorkommt.
Also diese Größenabschätzung. Also, und dann sehen wir
Ist gleich. Ja, ist ja dieses 10 mal N.
Und das ist offensichtlich Tetter von N. Das ist hier der
mittlere Fall. Das wächst genauso stark. Das ist ja
nur eine Konstante da. Also daraus wächst,
könnten wir folgern, wir haben Fall 2, das Mastertheoriens.
Und dann wüssten wir, dass das F von N
gleich Tetter von N. Log Annes.
Also in der Regel ist es so einfach
wie hier
Manchmal hat man den dritten Fall. Ganz häufig hat man
den zweiten Fall über den ersten Fall.
Gut. Okay. Damit können wir das meiste klären.
Und für sie ist das Prozedere jetzt wie folgt.
Also, sie haben einen Algorithmus mit einer Rekussion drin.
Sie müssen als allererstes immer die Rekurrenzgleichung aufstellen.
Also diese Gleichung aufschreiben. Das machen sie immer.
Dann gehen sie wie folgt vor. Schritt 1 ist,
sie prüfen, ob sie das Mastertheorium anwenden können.
Sie gucken, ob ihre Funktion von dieser Form ist.
Wenn ja, rechnen sie A und B aus und überprüfen
die drei Fälle
Wissen, welche Größenordnung die Funktion hat. Wenn die Funktion nicht dieser Regel folgt,
versuchen sie mit der Substitutionsmethode herauszufinden, wie das Wachstumsverhalten ist.
Das haben wir gemacht an dem ersten einfachen Beispiel. Wenn das nicht geht,
weil die Rekurrenz zu kompliziert ist, versuchen sie,
einen Rekursionsbaum aufzustellen und das Ebene für Ebene zu addieren und
auf diese Art zu einer geschlossenen Formel zu kommen.
Wenn das auch nicht geht, dann lassen sie es.
Okay. Kommt hier nicht vor
Okay, so. Ja, soweit so gut. Und
ich muss ihn natürlich noch irgendwie ein tolles Beispiel zeigen.
Das war jetzt alles so theoretisch und ist irgendwie doof.
Also wir machen jetzt ein schönes Beispiel. Und zwar machen
wir das folgende Problem, schauen wir uns an.
Sie haben es zu viel Geld gebracht, investieren tatkräftig an der Börse,
analysieren das Verhalten ihrer Aktien, die steigen und schwanken immer so.
Und im Nachhinein würden sie gerne wissen,
was wäre eigentlich die ideale, der ideale Zeitpunkt gewesen,
um die Aktie zu kaufen und wieder zu verkaufen,
um den Gewinn zu maximieren
Das löst man mit dem Maximum Subarray-Problem. Das Problem ist wie folgt,
wir haben also eine Folge X von einem ganz engen,
ganzen Zahlen, das ist also die Schwankungen des Börsenkurses,
wenn sie so wollen.
Und wir suchen die Teilfolge aus dieser Folge X,
deren Summe maximal ist. Ja, wenn wir die maximale Teilsumme.
Also wir haben N gleich 10 hier in diesem Beispiel.
Hier ist eine Folge von Zahlen,
also am ersten Tag ist es so ein 3 Euro gestiegen,
wahrscheinlich um 3.000 Euro, dann um 4.000 gefallen,
um 5 gestiegen,
2 gestiegen,
minus 5 und so weiter
Und sie sind interessiert, was ist denn das Intervall mit dem größten Summe, ja, dem größten Entscheidung.
Das kann ab und zu zwischendurch mal vielleicht ein bisschen kleiner werden, aber insgesamt wollen sie die größte Summe haben. So,
es wäre also in diesem einfachen Beispiel wäre es,
wenn sie zum Beispiel das Intervall von 1 bis 4 nehmen,
wenn sie 3, minus 4 plus 5 plus 2 wäre 6,
wenn sie das Intervall von 3 bis Sieden nehmen,
hätten sie 5 plus 2,
minus 5 plus 6 plus 9, ist 17. Und ja,
wenn sie jetzt ein bisschen hier rumgucken,
dann sehen sie auch relativ schnell,
dass dieses Intervall die maximale Teilsumme ist
Okay, wir brauchen einen Algorithmus, dir dieses Problem löst.
Erste Möglichkeit. Es ist immer ganz gut mit einem relativ naiven Algorithmus
anzufangen, dann hat man das Problem schon mal gelöst.
Dann hat man schon mal was,
wo was rauskommt und vielleicht ist ja okay,
vielleicht haben sie immer so kleine Eingaben und dann spielt es keine Rolle,
ob das lange dauert oder nicht.
Und die einfachste Art zum Problem zu lösen, ist einfach alles ausprobieren.
Das ist immer eine gute Strategie in der Informatik.
Erstmal alles ausprobieren, dann wissen sie, dass sie die
richtige Lösung irgendwo dabei gehabt haben und dann werden sie die finden,
wenn sie darüber maximieren.
Also Algorithmus 1, probiere alle Möglichkeiten
Wir brauchen vier Variable. Wir haben U für die untere Grenze
der Teilsumme und O für die obere Grenze der Teilsumme.
Wir haben Teesum für die aktuelle Teilsumme, die wir betrachten.
Und wir haben Max-Teesum für die maximale Teilsumme.
So sieht das aus. Das ist der Algorithmus,
Teilsumme von X. X ist also das Array.
Die maximale Teilsumme wird am Anfang initialisiert mit null.
Also wir haben noch keine gefunden. Und im Zweifelsfall
ist dann besser die Aktie gar nicht zu kaufen.
Dann haben sie auch null Gewinn gemacht
Okay, so, dann haben wir zwei Vorschleifen und die Vorschleifen
probieren alle Möglichkeiten zwischen Untergrenze und Obergrenze aus. Ja,
die Untergrenze, die läuft von 1 bis der zur Länge des Arrays,
ja, X.Lenks ist die Anzahl der Zahlen,
die wir da haben, N, ja,
und die Obergrenze, die muss natürlich rechts von der Untergrenze anfangen,
die geht von der Untergrenze bis X.Lenks,
also bis zum Ende des Arrays immer, ne.
So, dann müssen wir ausrechnen, ja,
wie viel ist denn jetzt diese Summe zwischen U und O.
Ja, das machen wir in dieser dritten Vorschleife,
da haben wir einen Vorschlag für die Variable I und dann rechnen wir,
die geht von U bis O und die Teilsumme ist dann immer die Teilsumme plus X von I, also das ETE-Element aus dem Array.
Die maximale Teilsumme ist dann das Maximum aus der bisher berechneten maximalen Teilsumme und der Teilsumme.
Okay, und dann können Sie die zurückgeben, ergebnisberechnet Finish.
Der Algorithmus hat eine Laufzeit, die hat ein Wachstum wie N
hoch 3. Also die Laufzeit TP von N,
also P ist unser Algorithmus, CP von N.
Bei N ist die Größe des Arrays, ist O von N hoch
3. Es ist sogar Tetter von N hoch 3,
aber das werde ich Ihnen hier nicht zeigen.
Okay, so, warum ist das O von N hoch 3?
Also wir haben hier eine Schleife, die wird N mal durchlaufen,
ne, die hier. Dann haben wir hier eine Schleife,
die wird nicht ganz so häufig durchlaufen,
die wird N-U plus einmal durchlaufen,
aber wir sind mal großzügig und sagen, das ist kleiner gleich N,
also im Wesentlichen wird die auch N mal durchlaufen.
Das wird am Ende immer ein bisschen weniger,
aber Wir sagen, es ist auch einmal.
Dann haben wir eine dritte Schleife, die geht von U
bis O. Die wird also u-min-o-minus-u plus einmal durchlaufen.
Und auch hier schätzen wir mal großzügig ab und sagen,
das ist kleiner, gleich en. So,
und wenn wir drei Schleifen, haben die ineinander geschachtelt sind,
die jeweils Endzeit benötigen, dann ist die Gesamtzeit,
die am Ende entsteht, proportional zu N hoch 3. Ja,
das ist, glaube ich, nachvollziehbar.
Sie müssten jetzt theoretisch noch ein bisschen skeptisch sein,
ob das nicht vielleicht zu grob abgeschätzt ist,
weil wir natürlich hier, das jeweils die Anzahl der Schleifendurchläufe abgeschätzt ist.
Ich kann Ihnen aber sagen, Sie können nachweisen,
es wächst tatsächlich genau wie N hoch 3. Ja,
diese Summe hier
Okay. Was glauben Sie,
was Sie auf einem heute aktuellen PC,
so ein Modell hier, so ein schickes,
was Sie damit so schaffen können in einer Minute?
Was für ein N? Eine Minute Laufzeit.
Wie groß kann das Array werden?
Wer ist für
Ich wollte eine Zahl hören. 10 auf 6. Ja.
10 auf 4. 7 mein 10. 4. 10.
2. Wer glaubt, wesentlich weniger als 10. 4?
Wer glaubt wesentlich mehr als 10. 4? Okay. Sie sehen,
es ist nicht so einfach, das zu schätzen.
Ich meine, Sie wissen natürlich auch nicht,
was hier für ein Prozessor drin ist und so.
Aber okay, das ist der naive Algorithmus und ich sage Ihnen,
es ist eine tatsächlich relativ frustrierend kleine Zahl,
was Sie in einer Minute machen können.
Und wir werden noch dazu kommen.
Aber es gibt einen guten Grund, diesen Algorithmus zu beschleunigen
Und wir müssen überlegen, ob wir es schneller können.
Hier ist Variante 2. Informatiker machen ganz gerne die White and Conquer.
Wer von Ihnen jetzt schon mal von Wie weit and Conquer gehört?
So einige, ne? Auch relativ viele schon.
Also die White and Conquer ist im Prinzip,
wo wir sagen, wenn wir keine Ahnung haben,
wie wir das Problem lösen sollen, machen wir das so.
Wir teilen das Problem in zwei Hälften.
Wir lösen das Problem auf der linken Seite. Wir lösen
das Problem auf der rechten Seite. Wir überlegen uns,
was an diesem Schnitt passiert zwischen den beiden Teilproblemen.
Und dann fügen wir alles zusammen. Die weiteren Conquer kann man
auf dieses Problem anwenden. Und wenn wir das machen,
dann sieht das so aus. Wir sagen, okay,
wir teilen unsere Folge X in der Mitte,
waren wir eine linke Folge und eine rechte Folge
Die erste, also die maximale Teilsumme ist ja jetzt irgendwo
verteilt in diesem X, ne? Irgendwo muss die sein
. Die kann entweder komplett auf der linken Seite sein,
dann ist es einfach, dann rufen wir rekusiv den Algorithmus
ja für die linke Seite auf, kriegen die maximale Teilsumme.
Wir wissen, dass das Maximum sind fertig. Die könnte
auch auf der rechten Seite sein, dann gilt das Gleiche.
Wir berechnen natürlich auch die maximale Teilsumme der rechten Seite.
Und wenn sie auf der rechten Seite wäre,
würden wir das bestimmen in dem rekusiven Aufruf,
hätten das das Ergebnis, wären fertig.
Könnte natürlich auch sein, dass diese maximale Teilsumme über diesen Schnitt
hier in der Mitte geht, wo wir es durchgeteilt haben.
Die fängt also in L an und hört irgendwo
in Er auf
In dem Fall ist es ein bisschen blöd.
Dann müssen wir nämlich irgendwie den linken, ne,
den rechten Teil der linken Hälfte kombinieren mit dem linken Teil der rechten Hälfte.
Zu einer großen Summe. Kann man aber machen und das machen wir so,
dass wir einfach mal sagen,
wir machen erst eine Vorberechnung und zwar ausgehend von dem Schnitt berechnen wir,
was ist denn die größte Teilsumme, die wir von hier an berechnen können,
wenn wir von hier nach links wandern.
Weil wir wissen ja, wir müssen dieses Element dabei haben,
sonst können wir die beiden ja gar nicht kombinieren
Das nennen wir mal eine Randteilsumme.
Da können wir eine linke und eine rechte Randteilsumme berechnen.
Der Algorithmus heißt RTS links in dem RRX,
geht von El bis R und es findet die maximale Randteilsumme.
Das ist wesentlich einfacher, weil wir eine Grenze schon kennen.
Und jetzt müssen wir nur gucken, was ist in die andere Grenze.
Und wir brauchen also nur eine Vorschleife, um das zu berechnen.
Wir sagen dann, dass El Max ist null,
Summen ist erstmal null und dann reden wir mit dem I
von der Position L zu R und wir rechnen auf der Summe
immer das X von I drauf und maximieren über diese verschiedenen Summannen und dann kriegen wir entsprechende Maximale Randteilsumme.
Sie sehen schon, der Algorithmus hat nur eine Vorschleife.
Laufzeit ist linear mit der Größe des Aris, also O von M.
So, das Gleiche machen wir für die andere Seite auch.
Und jetzt müssen wir nur alles kombinieren zu einem Devide in Konka-Verfahren.
Also, das ist unser Teilsummen-Algorithmus. Der kriegt dieses ARAX
als Eingabe und der kriegt zwei weitere Parameter L und R,
weil wir den jetzt rekusiv aufrufen und wir sagen immer,
von wo bis wo, das Array ist, was wir jetzt gerade betrachten wollen.
Am Anfang rufen wir das auf mit 1 und N oder x.lenks
, wenn sie so wollen
Okay, wenn L gleich R ist, dann hat unser Array
nur einfällt. Ja, wenn wir ein Feld haben,
ist die Antwort einfach, dann ist es entweder der Wert,
der in dem Feld steht oder es ist null für den Fall,
dass da was Negatives drinsteht.
Das andere macht keinen Sinn. Das sind die einzigen
beiden Teilzoomen, die es gibt, alles oder nichts.
Anderenfalls führen wir jetzt das Devite and Conquer durch,
wir teilen das Array an der Position M,
das machen wir bei L plus R halbe,
nach unten abgerundet, also irgendwo in der Mitte,
das ist Arrays, halbieren wir das.
Und jetzt lösen wir die beiden Teilprobleme,
das Linke und das Rechte,
wir berechnen also die maximale Teilsumme auf dem linken Array von L
bis zur Position M und auf dem rechten Teil Array von M plus 1 bis zur Position R.
Das ist der rekursive Schritt hier. Zwei rekursive Aufrufe.
Dann berechnen wir die Randteilsummen auf der rechten und linken Seite
und die beiden müssen wir addieren und dann wissen wir,
was ist die maximale Teilsumme, die über diese Mitte geht.
Und jetzt müssen wir nur alles zusammenfügen. Das heißt,
wir bilden das Maximum, der maximalen Teilsumme links,
maximale Teilsumme rechts und der Mitte
Das ist die maximale Teilsumme, die da rauskommt.
Das ist der Algorithmus. Das sind die drei Fälle,
die wir hier betrachten müssen. Okay, der Algorithmus löst das Problem auch.
Und Laufzeit. Ist das schneller als Enhof 3? Das können wir leicht rausfinden,
indem wir eine Rekurrenzgleichung aufstellen und sagen,
unser Devite and Conquer-Verfahren von En, das benötigt konstante Zeit,
wenn das N gleich eins ist, hier N gleich eins,
nur ein Element in dem Array,
linke rechte Grenze ist gleich,
ein Aufruf,
konstante Zeit
Wenn das N größer ist, dann haben wir zweimal
Tee von Devide in Gonker, von Nen halbe.
Wir halbieren ja das Array, die Größe wird also
noch halb so groß, plus zehnmal N.
Warum? Weil wir machen zwei rekursive Aufrufe,
jeder rekursive Aufruf hat die Laufzeit Tee von Nen halbe.
Und wir müssen die beiden Randteilsummen berechnen.
Und das kostet jeden Fall jedes Mal zehnmal irgendwie Endzeit.
Also Constante mal N.O. von Endzeit. Du hast alles aufgeschrieben,
wäre also zweimal Tee von N halbe plus 10 mal N.
Jetzt arbeiten Sie strikt mein Protokoll ab.
Sie prüfen als erstes, ob das Master-Theorien anwendbar ist
und sind erfolgreich
Das heißt, sie sehen, aha,
das ist ja genau wie im Mastertheorie, also A,
mal T von N durch B, plus eine Funktion,
dann wissen sie, A und B ist gleich zwei und sie wissen,
die Funktion F und N ist gleich zehnmal N,
das ist O von N und hier stets zufällig schon,
ja, da kommt dann raus, Tetter von N,
Log N, ja, also, unser Algorithmus,
Lisa hier, braucht nur noch N-Login,
also das Laufzeitverhalten ist wie N-Login.
Ja, da stellt sich die Frage,
ob das wirklich gravierend ist oder nicht
Vielleicht lohnt es sich schon, vielleicht nicht, müsste man gucken.
Müssen wir in der Praxis mal ausprobieren. Aber die schwierige
Frage ist jetzt, haben wir das Problem optimal gelöst?
Ja, war es das? Ist das das Maximum,
was wir rausholen können? Oder gibt es noch einen Trick?
Von dieser Frage steht man als Informatiker leider verdammt oft.
Und man steht da und weiß nicht, ob es vielleicht doch noch besser geht.
Ich finde diese Lösung schon ziemlich gut. Und ich glaube,
Ich hätte nicht damit gerechnet an dieser Stelle, dass es noch besser geht.
Damit habe ich schon verraten, dass es noch besser geht.
Aber das Nächste, was man jetzt machen würde,
ist, wir überlegen uns erst mal,
wie viel Zeit benötigen wir denn mindestens,
um das zu Problemen zu lösen?
Das wäre eine untere Schranke. Und es gibt fast immer
eine triviale untere Schranke und die triviale untere Schranke ist, sie müssen alles lesen.
Sie müssen die Daten mindestens einmal lesen. Das heißt,
besser als linear können sie nicht werden,
weil wenn sie ein Element des Arrays nicht lesen könnte,
da ja gerade das Maximum drinstehen, ganz einfache untere Schranke.
Wir haben also eine Spanne zwischen Linearzeit und Nlock
Da können wir uns überlegen, lohnt es sich noch?
Diese Spanne zu schließen oder nicht? Kann man darüber nachdenken
. Also, darüber muss man im Einzelfall nachdenken.
Es ist überhaupt, also man könnte jetzt versuchen,
eine bessere untere Schranke zu finden, sauschwer, kann ich Ihnen sagen.
Man kann auch versuchen, einen besseren Algorithmus zu finden.
Und den gibt es. Und der geht wie folgt.
Den schaffen wir noch in drei Minuten. Das Verfahren,
was wir dafür brauchen, ist ein sogenanntes Scannline-Verfahren.
Scannline-Verfahren bedeutet, wir durchlaufen, dass Array nur einmal,
wir wollen Linearzeit erreichen, wir dürfen nicht mehr tun,
als einmal das Area angucken.
Mehr können wir uns nicht erlauben. Können wir uns
zweimal angucken, okay,
aber nicht gravierend mehr
Was wir machen ist, wir überlegen uns,
wir haben ja eben schon immer die Randsumme berechnet und überlegen uns,
ob wir dieses Verfahren nicht ausnutzen können,
um in einem Durchlauf das Maximum zu bestimmen.
Und das geht wie folgt, sie laufen einfach von links nach rechts,
das ist die sogenannte Scanline und ihr Ziel ist es,
dass das, was links vom Array ist,
das haben sie berechnet und da wissen sie die maximale Teilsumme und werden sie dann bei N angekommen sind,
haben sie das Ergebnis.
Und der Trick ist ganz einfach, sie merken sich zwei Dinge,
sie merken sich die maximale Teilsumme,
die sie schon gefunden haben und sie merken sich die maximale Teilsumme am Rand dieser Scanline.
Und dann gibt es nur zwei Möglichkeiten, wenn diese Scanline-Ein-Position
weiter nach rechts geht, ist die maximale Teilsumme.
Entweder die, die sie vorher hatten, oder es ist
die, die den rechten Rand enthält. Das heißt,
sie gehen von der Position I zur Position I plus 1,
maximale Teilsumme am rechten Rand, wir addieren I plus 1,
setzen das auf null, falls die Summe negativ ist,
dann ist es immer besser, gar nichts zu machen.
Und sonst nehmen wir einfach das Maximum von beiden.
Wenn die Scanline rechts angekommen ist, haben wir das Ergebnis berechnet.
Fats it. Hier ist der Algorithmus, der das Problem löst,
Scanline-Verfahren, führt zur Berechnung der Teilsumme,
maximale Teilsumme wird auf null gesetzt,
maximale Teilsumme am rechten Rand
auf null
Hier haben wir die Vorschleife, die geht einmal durch das Array,
wir berechnen die maximale Teilsumme am rechten Rand.
Das ist das Maximum, der maximalen Teilsumme am rechten Rand,
plus das letzte Element, was jetzt dazukommt,
oder null, wenn das negativ ist.
Und die maximale Teilsumme ist entweder die maximale Teilsumme,
die wir vorher hatten, oder die maximale Teilsumme am rechten Rand.
Und die gehen wir zurück. Der Algorithmus ist ziemlich simpel,
hat hier an N, also eine Schleife,
die über N geht,
alle anderen Schritte sind konstant,
Laufzeit ist Tetter von
Jetzt dürfen sie aufhören, den Algorithmus zu optimieren.
Besser als so wird es nicht gehen. Denn wir haben schon
die untere Schranke, dass der Algorithmus in mindestens Linearzeit benötigt.
So, meine Zeit ist um. Ich würde ihn ja
gerne jetzt schon zeigen, was das in der Realität bedeutet.
Aber das müssen sie sich dann verkneifen bis nächste Woche Mittwoch