Guten Morgen. Sie können mich hören. Hervorragend. Ich
mache mal die Tür zu. Okay, so, wir
kommen zur Algorithmik. Wir sind in der zweiten Vorlesung.
Gerade mal überlegen, was ich noch ankündigen muss für diejenigen,
die die Übungsgruppe aus organisatorischen Gründen wechseln mussten.
Das waren einige, die mussten in die Montagsgruppe.
Wer immer noch hier ist und es nicht weiß,
ist, das ist okay.
Also für die, die gewechselt haben, ist es okay.
Die Gruppe ist jetzt aber absolut am Anschlag
Wirklich der Anzahl der Studierenden. Also ich hoffe,
dass jetzt keiner mehr wechseln muss und dass es jetzt so bleiben kann.
Ja, heute die Übung findet statt.
Allerdings ist einer meiner beiden Übungsgruppenleiter ausgenockt und wir werden die
heute ausnahmsweise einmal zusammenlegen müssen, weil derjenige krank ist.
Und es ist aber nicht so schlimm,
weil wir in dieser Übung sowieso nur eine ganz rudimentäre,
erste Einführung machen,
so ein bisschen organisatorisches besprechen und dann ein paar Sachen zu Mathe-Grundlagen sagen,
die sie wahrscheinlich sowieso alle wissen.
Insofern macht das heute nicht
so viel
Ja, und ab nächste Woche läuft das dann alles normal.
Es ist, wo ist die? Das habe ich mir
auch gerade überlegt. Wir haben zwei Räume zur Verfügung.
Es ist eines in D220, ist das richtig?
Genau. Von den Demokraten, ja. Und F 000.
Genau. Und da ich F 009 nicht kenne,
und D125 meines Wissens groß genug ist,
habe ich gesagt, wir machen das in D. Okay.
Gut, so, wir waren noch ein bisschen bei
der Wiederholung, so das Grundstudiums oder des Drittsemesterstoffs
Wir werden jetzt heute dann einsteigen. Das mache ich gleich noch zu Ende
und dann werden wir heute einsteigen in die provabilistische Analyse.
Da geht es also dann darum,
dass wir Wahrscheinlichkeiten in unsere Analyse des Algorithmus berücksichtigen werden.
Da wird es ein bisschen mathematisch. Es bringt das so
mit sich. Wir müssen dann ein bisschen mit Erwartungswerten rechnen.
Aber wir werden eine ganze Reihe von Beispielen sehen.
Man sehen kann, wie so eine Analyse dann entsprechend funktioniert.
Und dann, wenn wir noch Zeit haben,
werden wir uns auch schon etwas mit der amortisierten Analyse beschäftigen.
Das ist eigentlich eine ganz wichtige Technik,
die wir also in den folgenden ja,
in den folgenden Vorlesungen auch immer wieder einsetzen werden.
Das Propabilistische kommt ab und zu mal rein,
aber ist tatsächlich auch eine Technik, die ja für ein bisschen später gedacht ist.
So, noch ganz kurz zu Rekurrenzen, die wir für
die Beschreibung von Rekursivenfunktionen benötigen. Das macht man,
wie gesagt, auch schon ganz intensiv im dritten Semester.
Das werden wir hier auch relativ standardmäßig einsetzen.
Ich habe aus Ende letzter Vorlesung auch schon gezeigt,
also Rekurrenzgleichungen sehen so aus, wir beschreiben in die Laufzeit einer Funktion,
abhängig von einem Eingabeparameter N,
also von der begröße und tun dies quasi genau wie die
Rekursion im Algorithmus durch die Beschreibung der Funktion selber mit veränderter Eingabe.
Und das Hauptproblem bei der Beschreibung von Rekurrenzen ist nicht
das Aufstellen der Rekurrenz. Das ist immer ganz einfach.
Das kann man dem Algorithmus in der Regel sofort ab ansehen,
wie diese Rekurrenzgleichung gebaut werden muss.
Das spiegelt ja nur den Aufruf quasi wieder. Das Schwierige ist,
diese dann aufzulösen und in eine geschlossene Form zu überführen.
Wenn man so ganz einfache Gleichungen hat, wie diese hier,
dann ist eine ganz gute Technik die Substitutionsmethode.
Man setzt also für diese Funktion T von N mehrfach die Definition ein.
Also hier hätte man dann das erste Mal die Definition Tee von
NST von N minus 1 plus C1 und dann kann man
für Tee von N minus 1 die Definition nochmal einsetzen.
Das macht man mal so ein paar Mal und dann sieht
man in der Regel schon, was passiert,
also wie so ein Bildungsgesetz ist für die geschlossene Form.
Und dann überlegt man sich, wann man diesen Prozess terminieren kann,
weil wir am Ende hier bezüglich des Funktionsparameters am Rekursionsende angekommen sind.
Also bei dem Fall, wo wir hier die Konstante annehmen können.
Und wenn wir das machen, dann können wir daraus ganz schnell ableiten,
dass in so einem einfachen Fall ja,
wir nach hier in diesem Fall Endschritten nur noch TV1 haben,
also die konstante Zeit für das Rekursionsende.
Und dann haben wir endminus eins Aufrufe gehabt und jedes Mal haben wir
eine konstante C1 addiert und dann kommt da endminus eins,
mal C1 plus C0 raus, das ist ein O von Eng.
Okay, das ist natürlich nur die Herleitung der geschlossenen Formel.
Formell muss man die dann eben durch eine Induktionsbeweis noch überprüfen,
ob das auch wirklich stimmt. Hier ein Beispiel,
was schon ein klein bisschen komplizierter ist,
das ist eine Sache,
die man in Algorithmen ab und zu hat und zwar ein Laufzeitverhalten,
wo wir eine Funktion haben mit Eingabegröße N. Wir haben zwei rekursive Aufrufe und in jedem rekursiven Aufruf übergeben wir die Hälfte der Daten.
Also dann haben wir hier TVN-Halbe. Und dann haben wir
eine konstante Zeit in der Funktion selber.
Sie kennen sicherlich alle Devide in Conka,
weil die Vide in Conka hat man dieses Verhalten.
Das heißt, der Algorithmus wird in zwei Teile geteilt.
Die beiden Teile werden unabhängig voneinander ausgeführt.
Normalerweise ist der Input im Wesentlichen die Hälfte des ursprünglichen Inputs.
Und dann ist immer so ein bisschen die Frage,
wie groß ist der Aufwand in der Funktion selber bei vielen,
die weiterhin Konka-Verfahren, ist das hier linear.
Mein Beispiel hier hat hier eine Konstante. Ja,
das sind so die beiden typischen Szenarien, die man hat.
Meistens ist es linear vom Aufwand hier, hier ist es jetzt gerade eine Konstante. Ja,
hier kann man auch so vorgehen,
dass man mal die Definition der Funktion ein paar Mal einsetzt,
dann würden wir also zweimal Tee von in halbe plus C
und für das Tee von in Heilbe hätten wir dann wieder zweimal Tee von N-Viertel jetzt,
weil wir es in jedem Schritt halbieren, plus C.
Und wenn man sich jetzt vorstellt, dass man das Ganze eh mal macht,
dann würde man diesen Faktor 2 jedes Mal bei jedem Einsätzen dazu gewinnen.
Das heißt, man hat hier was, was wächst wie zwei Hochi.
Und auf der anderen Seite würde man hier immer durch zwei dividieren.
Das heißt, der Übergabeparameter ist von der Ordnung N durch zwei Hochi.
Und in jedem Schritt würde man dann hier konstanten addieren.
Die kriegen aber auch die Faktoren hier übergeben. Das heißt,
dann hätte man hier erstmal nur die Konstante C. Im nächsten
Schritt hätte man schon zwei C, dann 4C und so weiter.
Also hat man hier so eine Summe mit zwei Hochi-minus eins
mal C plus zwei ruinus zweimal C und so weiter.
Okay, dann wäre Das ist die Form, die wir hätten nach I schritten.
Und wenn wir das jetzt hier durch eine Summenformel beschreiben würde,
da stehen zwei auch IMAT von N durch zwei UI Plus
und dann die Summe hier von Karl gleich 0 bis I minus 1,
2 UK mal C.
Wenn wir diese Form hier stehen haben,
müssen wir uns als nächstes überlegen, wie viele Schritte brauchen wir,
bis wir hier das Rekursionsende erreicht haben und hier eine Konstante steht.
Und das ist hier ganz leicht zu sehen. Also wir
haben hier N durch zwei UI, wenn das Ganze eins wird,
wissen wir, dass wir das Rekursionsende erreicht haben.
Also müssen wir gucken, wann ist N durch zwei UI,
denn Wie lange ist es kleiner gleich eins?
Und das können wir umformen. Und dann sehen wir,
das ist so lange der Fall, wie ich größer gleich der Logorithmus,
sobald es zwei von N ist.
Gut, das können wir dann einsetzen in unsere Gleichung.
Wir setzen also das als den Maximalwert für I hier ein.
Dann wissen wir, dass die Laufzeit kleiner, gleich zwei hoch,
Logorithmus, sobald es zwei von N. TV1 ist.
Plus, und dann hier haben wir diese Summe,
C mal und die Summe von K gleich 0 bis Logrithmus zur Beiß 2 von N2OK.
Hier haben wir das schon im Prinzip ein bisschen abgeschätzt,
weil wir hier schon so Rundungsphänomene haben,
die dadurch zustande kommen,
dass natürlich die Zahl N hier nicht notwendigerweise eine Zweier-Potenz ist und der Logorithmus irgendwie eine gebrochene Zahl sein könnte.
Und in diesem Szenario müsste man das eigentlich aufrunden.
Das sind so Rundungsphänomene, die wir typischerweise dann ignorieren.
Ja, dann haben wir jetzt eine geschlossene Formel und das ist jetzt einfach aufzulösen.
Also zwei Hochlorhythmus zum Beispiel von N ist ja nichts weiter als N selber.
Tee von 1 ist eine konstante C und dann haben wir
zehnmal diese Summe und so eine Summe von Potenzen.
Das sollte ihnen in Zukunft schnell geläufig vorkommen.
Für die, die jetzt nicht so ad hoc wissen,
wie man das auflöst, das ist eine geometrische oder eine
exponentielle Reihe
Wir werden beide Begriffe für verwendet. Und dafür gibt es eine ganz einfache,
geschlossene Formel, nämlich die Summe von K gleich 0 bis N,
X hoch K, ist X hoch N plus 1,
minus 1 durch X, minus 1. Das gilt immer,
wenn X ungleich 0 ist.
Wenn es null ist, macht das auch nicht so viel Sinn.
Dann haben wir den Nenner null. Und die Tafel kann man
nie. Okay, und wenn wir das jetzt einsetzen,
dann sehen wir, dass das hier gerade 2N ist,
also 2N minus 1,
genauer genommen.
Zusammengefasst haben wir dann dreimal zehnmal N-C,
wäre also O von N. Das heißt,
wenn wir einen Divide-and-Konker-Verfahren haben mit einer konstanten Laufzeit in der Funktion selber,
also zwei rekursive Aufrufe, aber nur eine konstante Laufzeit in der Funktion,
selber die rekursiven Aufrufe mit N-Halbe an Datengröße,
dann erhalten wir ein Verfahren mit linearer Laufzeit im Endergebnis.
Übrigens gilt das auch für beliebige andere Teilungen der Eingabe.
Also sie können auch den Input in drei Teile aufteilen und dann
immer ein Drittel der Daten über geben oder in vier oder in sechs,
das ist völlig egal, wenn sie das hier machen,
dann sehen sie, dass sie hier immer den Logarithmus dann zu einer anderen Basis haben,
aber dann hier auch die Basis hier immer größer wird.
Und das hebt sich immer genau auf. Das heißt,
auch bei einem die weiteren Konka-Verfahren, das Teilen in mehrere Teile
bei dann entsprechender weiteren Verkleinerung der Daten bringt im asymptotischen keinen Laufzeitvorteil.
Das ist auch etwas, was sinnvoll ist, erstmal zu wissen.
Gut, also das ist die Methode der Wahl,
die wir so anwenden, dann brauchen wir theoretisch noch einen Beweis.
Den habe ich letztes Mal auch schon gezeigt, wie wir das machen.
Also das heißt, wir zeigen dann, dass unsere Formel gilt.
Das O-Kalkül lösen wir dadurch auf, dass wir sagen,
okay, die Laufzeit muss kleiner gleich eine konstante K jetzt mal N sein.
Und dann versuchen wir einen Induktionsbeweis. Und manchmal ist es
ein bisschen schwierig mit dem additiven Konstanten hier,
die dazu führen, dass die Induktion so nicht ohne weiteres funktioniert.
Und der Trick ist dann ein bisschen mit dieser Annahme herumzuspielen
und durchaus auch mal zu probieren, die etwas kleiner zu machen.
Nicht nur größere Schranken zu probieren,
sondern auch mal eine kleinere Schranke zu probieren,
weil man ja diese Schranke im Induktionsschritt immer in die Gleichung einsetzt und es dann teilweise besser funktioniert,
einfach wenn die ein bisschen kleiner ist.
Und dann kommt dann der Beweis in der Regel auch hin.
Ja, zwei weitere Tricks, die man noch anwendet im Kontext von Rekurrenzen.
Manchmal hat man relativ komplexe Situationen. Also hier ist so
ein Beispiel mal gezeigt, wo es sehr unangenehm ist,
wenn man hier anfangen würde durch eine Substitutionsmethode,
also da schrittweise etwas einzusetzen
Das ist hier eine Gleichung, wo wir TVN haben als zweimal Tee von Wurzeln.
Das ist nach unten abgerundet hier. Plus Logorithmus von N.
Also da würde man sich jetzt wirklich schwer tun, Sachen einzusetzen.
Und in solchen Situationen ist es immer gut, mal darüber nachzudenken,
ob man nicht die Funktion, diese Rekurrenzgleichung anders aufschreiben kann.
Einfach eine andere Funktion wählen kann. Und was in diesem Fall sehr hilft,
ist, wenn man quasi exponentiert oder andersrum gesprochen,
wenn wir statt dem N hier den Parameter 2 hoch M einsetzen.
Und er müsste dann natürlich nichts weiter als der Logorithmus von
N, also strenge neue Zweierlogorithmus von
Wenn wir das machen, dann wird diese Gleichung hier zu einer relativ einfachen.
Dann steht da nämlich TV2OM, ist gleich zweimal Tee von zwei UM halbe plus M.
Und das ist jetzt schon sehr ähnlich zu den Funktionen,
die wir auch schon gesehen haben,
wo also der Input sich halbiert von der Größe.
Und wir hier einen linearen Zeitanteil haben. Und wenn wir
jetzt noch diese Funktion Tee durch eine andere Funktion ersetzen,
wo wir sagen,
wir betrachten einfach die Funktion S von M,
die dann für Tee von zwei Hoch-Ems steht,
dann haben wir eine ganz einfache Gleichung stehen,
das S von M
nämlich zweimal S von M
halbe plus
Und das wissen wir schon,
das ist wieder die Wahrheit in Konka, diesmal mit linearem Aufwand,
im nicht-rekusiven Teil, also in dem Funktionsteil selber.
Und da kommt dann M-Log-M raus und dann können wir
rückwärts wieder für das M-Log-In einsetzen und dann wäre die Laufzeit
dieser Funktion mit dieser Rekurrenzgleichung O von Log-In, Log-Log-In.
Das zeige ich Ihnen hier der Vollständigkeit halber.
Auch diese Technik wird selten eingesetzt. Manchmal muss man
das machen, wir werden das auch nicht so intensiv benutzen
Eine andere Technik ist hingegen recht wichtig. Und zwar ist
das der Rekursionsbaum. Manchmal ist die Situation eben so,
dass man theoretisch natürlich einsetzen kann,
aber das Ganze auch sehr schnell in viel Rechnerei ausartet und man die Sache enorm vereinfachen kann,
wenn man sich einfach mal vorstellt,
wie die Rekursion abläuft und wie die einzelnen Aufwände dann in den Funktionen tatsächlich ist.
Denn die Situation ist häufig so,
dass auf einer Ebene in dieser Rekursion der gleiche Aufwand auftritt
und wie die Situation dann entschieden schärfen können,
indem wir quasi die Laufzeit über alle Funktionen einer Ebene aufsummieren.
Hier ist ein Beispiel, wie das funktioniert. Also wir
haben als Rekurrenzgleichung Tee von N gleich dreimal Tee von N Viertel plus CN Quadrat.
Und das kann man sich jetzt im Ablauf so vorstellen.
Wir haben einen Algorithmus, der braucht dann erstmal für sich selber,
also in dem Kernbereich C von N,
zehnmal N Quadrat viel Zeit.
Und dann kommen die drei rekursiven Aufrufe hinzu
Wie sieht man hier in dem Baum, durch die drei Kinder?
Und die drei Aufrufe haben einen Laufzeitbedarf von Tee von Enviertel.
Ja, und jetzt kann man sich überlegen, okay,
so ein rekursiver Aufruf, wie viel Zeit benötigt der dann?
Und dann wissen sie ja,
der Aufruf selber benötigt dann natürlich C von N-Viertelquadrat,
weil sie ein Viertel wieder einsetzen müssen.
Das gilt dann für jeden dieser rekursiven Aufrufe.
Und dann gibt es einen weiteren rekursiven Aufruf.
Das ist dann die nächste Ebene in diesem Baum.
Und dann haben sie hier C von 10 mal N-16
zum Quadrat an Laufzeit für jeden einzelnen rekursiven Aufruf
Ja, wie viele Aufrufe das sind, das kann man ja ganz leicht berechnen.
Wir haben drei Aufrufe in der Funktion selber.
Und dann haben wir auf der nächsten Ebene dann neun oder
drei Hochi im Allgemeinen, wenn wir wissen wollen,
wie viele das auf jeder Ebene am Ende sind.
Okay, und dann stellt sich aber am Ende wieder die gleiche Frage,
wie tief ist dieser Warm,
also wie häufig müssen wir einen rekrusiven Aufruf durchführen,
bis wir am Regressionsende angelangt sind.
Und das kann man jetzt auch
leicht berechnen
Wir müssen ja immer,
wir vierteln immer die Eingabe und da wissen wir schon,
wenn wir etwas immer vierteln,
dann können wir das genau Logorithmus zur Basis von viermal machen,
bevor wir dort eine Zahl kleiner gleich eins haben.
Und dementsprechend ist, dass die Höhe dieses Baumes hier.
Okay, und jetzt machen wir Folgendes. Wir addieren einfach
die Laufzeiten hier pro, also zeilenweise oder pro Ebene des Baumes.
Der Vorteil ist, wir wissen, wie viele Knoten wir in jeder Ebene haben.
Das sind eben drei Hochi bei Ebene I,
also 3 hoch 0, 3 hoch 1,
3 hoch 2 und so weiter.
Und wir wissen, die Laufzeit,
die wir pro Knoten in der Ebene haben und
die beiden Dinge können wir dann
entsprechend multiplizieren
Ja, das müssen wir dann nur noch aufsummieren und kriegen
auf die Art und Weise dann eine geschlossene Formel.
Hier unten müssen sie dann die Laufzeit abschätzen für das Ende der Rekursion,
also diese Funktion, die keinen rekursiven Aufruf mehr haben.
Ja, das sind immer Konstanten und dann ist nur die Frage,
wie viele das hier sind. Und wir wissen schon,
hier die Tiefe dieses Baums und können das dementsprechend ausrechnen und
hier kommt dann N hoch Logrhythmus zur Basis 4 von 3
Das ist nicht so richtig einsichtig hier. Ich war,
als ich es das erste Mal im Kormen gesehen habe,
habe ich selber total gestutzt, warum das da steht.
Dann habe ich gedacht, ja,
eigentlich müsst ihr da auch stehen, drei, ich weiß nicht,
ob sie das überhaupt lesen, dann ist es so klein.
Drei hoch Logorithmus zur Basis 4 von N. Das hätte man eigentlich erwartet,
weil wir wissen, ja, die Anzahl der Knoten,
die wächst ja immer um drei,
also um den Faktor 3 von Stufe zu Stufe.
Und wir haben Logorithmus-Debasis von 4 N viele Ebenen.
Deswegen sind das hier unten gerade drei hoch Logorithmus-Device 4 von
Viele Knoten und die haben jeweils konstante Laufzeit. Das ist
erst mal was anderes als das, was hier steht.
Allerdings kann man das umrechnen und wie das genau geht, steht hier.
Und das ist tatsächlich identisch mit N-Hoch-Logorithmus zur Bades 4 von
3. Sie können also beim Logorithmus durch zwei Umformungsschritte zeigen,
dass sie, wenn sie den Logorithmus im Exponenten haben,
quasi diese Zahl und diese Zahl hier vertauschen können.
Und das ist ganz praktisch, weil wenn sie das hier sehen,
dann wissen sie sofort, na, das ist eine Zahl,
irgendwas von eine 0,8, glaube ich, oder so.
Ja, also das ist dann irgendwie kleinergleich, ja, end.
Also dann müssen sie, das ist hier schwerer zu sehen.
Da weiß man nicht so genau, wie es ist.
Okay, gut. Auch mit diesem Rekursionsbaum kriegt man natürlich erst mal
nur die Intuition, wie diese geschlossene Formel aussehen müsste.
Und die muss man natürlich dann auch noch wirklich berechnen.
Also wir wissen dann jetzt,
dass das T von N ist dreimal T von N Viertel
plus CN-Quadrat und mit Hilfe des Baumes
Haben wir jetzt gesehen, dass wir das ebenenweise addieren können.
Und dann haben wir CN-Quadrat plus 3,
16. CN-Quadrat plus 3, 16. zum Quadrat-CN-Vorrat und so weiter.
Und zwar geht es dann so lang,
bis wir dann drei Sechzehntel hoch Logorithmus,
so war es 4 von N, minus 1,
also die vorletzte Ebene, CN-Quadrat haben.
Und dann noch die ganzen Knoten mit der konstanten Laufzeit am Ende.
Okay, das können wir als Summenform schreiben, dann steht
da das. Haben wir die Summe von Igarch 0,
bis Logorithmus zu war es 4 von N minus 1,
3, 16. lug ihm als CN-Quadrat.
Und hier die Abschätzung für den Rest, für die westlichen Blätter.
Das schätzen wir ab. Also es ist hier ein bisschen gröber abgeschätzt,
weil es auch keine große Rolle mehr spielt für die Laufzeit.
Wir haben die Summe hier, lassen wir bis unendlich
laufen und haben dann hier 3-16tel Hochi.
Dafür gibt es eine geschlossene Formel wieder.
Es ist die unendliche geometrische Reihe in diesem Fall.
Und dann haben wir hier vorne eine Konstante, also 1-minus,
1-0 durch, 1-minus 3-16tel.
CN-Quadrat und dann der Teil hier. Und das ist der
kleinere Teil, das wächst schwächer als N und dann bleibt
ja als Laufzeit genau N-Quadrat übrig
Ja. Auch hier kann man ein bisschen ruminterpretieren,
was passiert, wenn man an diesen Konstanten hier dreht.
Und das Entscheidende ist offensichtlich hier, dass das Verhältnis so ist,
dass der Teil, den wir haben,
kleiner ist als die Anzahl der Aufrufe, damit der,
damit diese Herleitung so immer funktioniert und die gleiche Laufzeitklasse herauskommt.
Die Laufzeit wird dominiert offensichtlich durch die Laufzeit,
die wir brauchen, in dem, ja,
in der Funktion selber.
Das ist CN-Quadrat
Gut. So, auf diese Art und Weise können wir
Rekurrenzen auflösen. Das letzte, das letzte Stückchen,
was es hier noch zu zeigen gibt zu dem Thema,
ist das Mastertheorie, was sie sicherlich auch schon mal irgendwie gehört haben.
Hoffe ich jedenfalls, dass quasi einfach nur die Auflösung der generischen Referellen,
der generischen Rekurrenz TVN gleich C für Endlich 1 oder A
mal T von N durch B plus eine Funktion F&N ist.
Wobei die C eben die übliche Konstante ist für einen
kleinen Input und A und B, zwei Konstanten ist,
die man beliebig steuern kann und F von N eben eine Funktion.
Und für dieses Szenario,
was wir einfach in der Algorithmenentwicklung ganz häufig haben,
kann man einfach das schon vorberechnen, was rauskommt,
wenn man die Rekurrenz auflöst und dann kann man das einfach nur einsetzen.
Und das Mastertheorium sagt eben, wie wir das auflösen können
und welche Laufzeitklasse herauskommt in diesem Fall.
Und wir müssen unterscheiden dann zwischen drei möglichen Fällen.
Wir müssen uns anschauen, wie ist das Verhältnis der
Laufzeitfunktion F von
Zu diesen konstanten A und B. Weil das ist entscheidend für die Laufzeit der Funktion.
Wenn, also was wir berechnen, ist Logorithmus zur Basis
B von A. Logorithmus zu BSB von A,
wenn wir mal hier auf unseren Baum gucken.
Ja, hier haben wir A und B,
dann sehen wir, das spielt hier auch ständig eine Rolle.
Also dieses Verhältnis von hier sehen wir es.
Von der Anzahl der Teile,
in dem wir das Projekt zerlegen und die Größe des Inputs
für den Teilaufruf
Okay, so, wenn das F&N also in einer Laufzeitklasse ist,
die kleiner ist als N-Hochlogorithmus zu Basis B von A,
dann, also kleiner, also noch mit dem Y runtergerechnet,
dann ist das T von N immer gleich Täter von N-Hochlogorithmus zu Basis
B von A. Wenn es genauso stark wächst,
die Funktion F&N wie N-Hochlogorithmus zu Basis B von A,
dann haben wir diese berühmte N-Log-N-Laufzeit, die wir in
so vielen Algorithmen sehen, in Sortierverfahren, etc.,
also N-Hochlogorithmus-Zuweis B von A, Block-in Und der dritte Fall ist,
dass wir hier ein stärkeres Wachstum sehen,
als N-Hoch-Logorithmus zur Weiße B von A. Sie ist noch in Äpfelon da drauf.
Und dann müssen wir noch so eine Zusatzbedingung hier überprüfen,
damit dieser Fall gilt. Und wenn diese Zusatzbedingungen hier erfüllt ist,
dann wird die Funktion vollständig durch F&N dominiert.
Und dann ist die Laufzeittäter von F&N. Das sind die drei Fälle,
die das Mastertheorien quasi schon abdeckt und wo wir dann immer,
wenn wir diese Funktionsaufbau sehen,
direkt quasi die Laufzeitklasse ableiten können
Ja, damit hätten wir auch zum Beispiel unser erstes,
nee, unser zweites Beispiel angucken können, ja,
das sah ja so aus,
zweimal Tee von in halbe plus C und dann sehen wir,
dass A2 ist und B ist 2 und die Funktion F von NSC,
eine Konstante, um dann das Mastertheorium anzuwenden,
müssen wir erstmal den Logorithmus zur BSB von A ausrechnen,
das ist hier eins und dann müssen wir bestimmen,
welchen Fall wir haben und dann sehen wir,
dass die Funktion F von Enya eine Konstante ist und die ist von der Ordnung her kleiner als N hoch 1 minus Y und dann wissen wir,
dass wir den ersten Fall haben, Und dann wissen wir,
dass die Laufzeit der Funktionen in Täter von Ellen Hochlobbythmus,
so weiß B von A ist.
Und das war ja gerade eins, also es ist ein linearer Algorithmus.
Gut, das hatten wir aber vorher schon mit der Substitutionsmethode auch selber herausgefunden.
Okay, das war quasi Wiederholung zum Thema Okalkül und gerade
die Anwendung des Okalküls im rekusiven Fall, also bei der Anwendung rekusive Algorithmen.
Ich bin hier relativ schnell durchmarschiert durch dieses Thema,
wenn Sie das Gefühl haben,
oh, Da ist noch das ein oder andere,
was sie nicht so gut kennen oder können,
dann würde ich vorschlagen,
dass sie sich das noch mal genau anschauen und sich das noch mal durchlesen im Kormen oder auch in anderen Büchern,
weil wir das immer wieder anwenden werden.
Das ist so ein bisschen unser Handwerkszeug in den nächsten Vorlesungen.
Okay, so, jetzt kommen wir zur Neuen.
Und zwar zur propabilistischen Analyse. Was wir machen wollen,
ist, wir wollen, naja, weiter Algorithmen analysieren.
Wir wollen sie in ihrer Laufzeitklasse bestimmen.
Das hat sich jetzt erst mal nicht geändert
Was sich hingegen ändert, ist,
dass wir uns etwas genauer mit dem Input auseinandersetzen.
Und das führt uns dann zum sogenannten Average Case,
also zum mittleren Fall. Die Laufzeitanalyse, die wir
bisher gesehen haben, ist im Wesentlichen eine Worst-Case-Analyse gewesen.
Wir haben für jeden Schritt immer den ungünstigsten Fall angenommen.
Wenn wir jetzt sagen, wir wollen aber das mittlere Laufzeitverhalten bestimmen,
dann müssen wir uns mit dem Input auseinandersetzen.
Und streng genommen müssen wir über jede mögliche Eingabefolge mit einer
festgegebenen,
vorgegebenen Länge
Die Laufzeit bestimmen und darüber mitteln. Das wäre quasi die
mittlere Laufzeit, die wir bestimmen müssen.
Und dafür brauchen wir ein bisschen Techniken, um das zu machen,
weil das schon für einfache Algorithmen schwierig wäre, jede mögliche Eingabefolge zu analysieren.
Ja, wenn sie zum Beispiel ein einfaches Sortierverfahren nehmen,
dann müssen sie jede mögliche Reihenfolge der Daten betrachten,
um dann hier herauszufinden, was der Average Case ist.
Das ist ein bisschen unpraktisch und deswegen brauchen wir ein paar
Techniken, um das geschickter zu machen.
Es gibt ein zweites Anwendungsszenario. Es hat sich in den
letzten Jahren in vielen Bereichen herausgestellt,
dass man enorm gewinnen kann bezüglich der Einfachheit von Algorithmen, wenn man Zufallzahlengeneratoren verwendet.
Und dadurch Algorithmen quasi randomisiert. Da muss man jetzt ein bisschen aufpassen,
weil der erste Gedanke, den man da hat,
wenn man das hört, ist,
oh ja, das sind dann so heuristische Verfahren,
die raten dann irgendwas und liefern uns irgendein Resultat.
Und wir wissen dann natürlich nicht genau, ob das eine optimale Lösung ist.
Wenn sie kürzeste Wege berechnen wollen und sie würden da mit dem Zufallzahlengenerator irgendwas raten,
dann hätten, würde ja vielleicht nicht der kürzeste Weg da rauskommen.
Das ist nicht gemeint bei randomisierten Algorithmen,
die randomisierten Algorithmen garantieren, genau wie die deterministischen Algorithmen,
die sie wahrscheinlich hauptsächlich kennen, nach wie vor quasi,
dass sie das korrekte Ergebnis erhalten.
Das ist eine Eigenschaft, die sie haben müssen.
Sie werden nur in ihrem Prozess Zufallszahlen ein an,
um zum Beispiel sicherzustellen, dass die Eingabe in einer wirklich zufälligen Reihenfolge ist.
Quicksort kennen Sie bestimmt alle aus dem Grundstudium, ist ein
schönes Beispiel. Bei Quicksort gibt es halt Ungünstige Fälle,
wo die Laufzeit im Worst Case dann lang wird.
Also Quickshort hat im Worst Case in der Standard-Implementierung,
O von N-Quadratzeit. Nicht O von N-Log-in. Und
diese ungünstigen Fälle können natürlich gehäuft auftreten bei Anwendungen.
Da haben sie dann die Situation, dass aus den Randbedingungen,
wie das Sortieren verwendet wird, gerade dieser Fall häufig eintritt.
Zum Beispiel ist es so, dass bei einigen Quickshort-Varianten die
sortierte Eingabefolge ungünstig ist und sie dann quadratische Laufzeit kriegen.
Und es können viele Anwendungen geben,
wo ihre Eingabe mehr oder weniger schon fast vollständig sortiert ist
Zahlengeneratoren werden dann eingesetzt, um einfach sicherzustellen, dass sie wirklich eine zufällige Eingabefolge haben.
Und das wirkt sich dann auf die Analyse des mittleren Falls aus.
So, komm, gibt es ein schönes, einfaches Beispiel,
um zu zeigen, wie so eine Analyse des mittleren Falls aussehen kann.
Wir machen Folgendes. Wir haben einen Algorithmus, der iterativ
ein Optimum sucht. Das kennen Sie sicherlich,
wenn Sie einen Array haben mit Daten und Sie suchen jetzt das Maximum,
dann macht man das typischerweise so,
dass man mit einer Vorschleife über alle Elemente des ARAS drüberläuft und immer dann,
wenn die Array-Position größer ist,
als das aktuell gefundene Optimum dann aktualisieren sie diese Informationen und dann finden sie natürlich das Optimum.
So, das ist also dieser einfache Algorithmus, um ein Optimum zu bestimmen,
aus einem Array und der steht im Prinzip hier.
Also wir haben eine Variable für das aktuelle Optimum,
ist am Anfang null. Dann haben wir die Vorschleife,
die geht jetzt über das Array von 1 bis N und immer dann,
wenn AI größer ist als das aktuelle Optimum,
dann setzen wir das aktuelle Optimum auf AI.
So, das würde jetzt erstmal
nur das Optimum bestimmen
Jetzt könnte es sein, dass dieses Verfahren eingebettet ist in einem komplexeren Algorithmus.
Und dieser komplexere Algorithmus hat einen Anteil, der sehr laufzeitintensiv ist.
Der heißt hier do something expensive. Wir wollen gar nicht festlegen,
was da in dem Algorithmus passiert,
aber wir gehen einfach davon aus, es ist etwas,
was uns sehr viel Zeit kosten wird.
Die Zeit, die wir benötigen für diese Funktion hier,
die beschreiben wir nur durch eine Konstante.
Das ist die Konstante C-DSE,
do something expensive
Wenn wir jetzt uns überlegen,
welche Laufzeit hat denn jetzt unsere sequenzielles Optimieren hier,
dann sehen wir, ja, also diese sehr,
sehr teure Funktion hier, die müssen wir immer dann aufrufen,
wenn AI ein neues Optimum darstellt.
Wenn AI hingegen kleiner ist, als das schon gefundene Optimum,
müssen wir die Funktion nicht aufrufen. Die Worst-Case-Analyse würde sagen,
tja, also im ungünstigsten Fall ist unser Array-AI aufsteigend sortiert.
Dann wäre es so, dass in jedem Aufruf dieser,
oder in jeder Iteration dieser Vorschleife Und diese Bedingungen in dem If-Statement weiß,
also AI ist dann immer größer als das bisher gefundene Optimum.
Und wir müssen immer unsere sehr teure Funktion aufrufen. Okay,
Worst-Case-Analyse ist also klar, wir haben also irgendwie O von Enside für
diese Vorschleife und das Abarbeiten, das haben wir sowieso.
Und wir gehen davon aus, dass im Worst-Case in jedem Aufruf
diese If-Bedingungen wahr ist und wir diese teure Funktion ausführen müssen.
Das heißt, wir hätten als Laufzeit O von N plus N
mal diese Konstante CDSE oder das wäre dann O von N
mal CDSE
Jetzt könnten sie sagen, ja,
das ist ja eine Konstante, ist also O von N,
das ist richtig, aber diese Funktion hier,
die muss ja nicht notwendigerweise konstant in N sein.
Die könnte ja auch sowas wie ein Quadrat oder N
hoch 3 oder so beinhalten als Laufzeitklasse.
Insofern habe ich bewusst, dass hier als Konstante jetzt stehen gelassen,
um zu sehen, wie sich das Ganze auswirkt.
So, das wäre unsere Worst-Case-Betrachtung dieser Funktion. Und dann stellt sich
die Frage, ist das eine gute Analyse oder nicht?
Die ist auf alle Fälle korrekt und sie ist irgendwie auch
scharf, weil der Fall kann ja eintreten.
Es kann ja tatsächlich sein, dass die Eingaben aufsteigend sortiert
sind und wir jedes Mal diese teure Funktion aufrufen müssen.
Und dann ist die Laufzeit eben so hoch. Wenn wir aber davon ausgehen,
dass dieses Array irgendwie zufällig ist bezüglich der Reihenfolge, dann ist der Fall,
dass wir eine aufsteigende Sortierung haben, eher unwahrscheinlich.
Wir können überlegen, wie viele Reihenfolgen gibt es,
die wir annehmen können? Es sind N-Fakultät, viele.
Und nur eine von diesen Endfakultät vielen Möglichkeiten ist so,
dass wir den Worst Case erreichen.
Und weil den anderen haben wir irgendwie eine niedrigere Laufzeit.
Das heißt, wenn wir uns fragen,
wie lange dauert das denn so im Schnitt,
im Mittel
Ist das eine extrem schlechte Abschätzung. Und hier stellt sich
die Frage, können wir das besser machen? Können wir
das besser abschätzen? Offensichtlich können wir das nicht mit den Methoden,
die wir bisher haben, weil um jetzt eine bessere Laufzeitabschätzung zu bekommen,
müssen wir erst mal uns Gedanken darüber machen, wie häufig wir diese Funktion aufgerufen.
Das können wir aber nicht über den Eingabeparameter enden beschreiben,
weil N sagt ja nur,
wie viele Daten wir haben und wie häufig diese Funktion aufgerufen wird.
Hier hängt davon ab, wie die Daten verteilt sind.
Okay, also Worst Case tritt nur ein,
wenn A aufsteigen sortiert ist und wir interessieren uns für
die Laufzeit im mittleren Fall
Wenn wir über den mittleren Fall reden,
müssen wir natürlich etwas sagen, wie häufig welche Eingabe vorkommt.
Wir müssen nicht nur betrachten, welche Eingaben gibt es?
Die müssen wir nicht alle, nicht nur alle der Reihe nach betrachten.
Wir müssen sogar schauen, welche Eingabe tritt wie häufig auf.
Wenn wir das machen, dann gehen wir normalerweise immer von einer Gleichverteilung aus.
Wir sagen dann, jeder Fall, der fortkommen kann,
ist gleich wahrscheinlich. Das ist in der Praxis eher unrealistisch.
Also wenn sie sich mit solchen Problemen auseinandersetzen,
haben sie ganz selten in der Praxis wirklich randomisierte Eingaben.
Ja, sie haben immer irgendwelche oder ganz,
ganz häufig irgendwelche Nutzer oder anwendungsspezifischen Vorgaben, die dazu führen,
dass diese Daten eben nicht rein zufällig sind.
Das ist also eine Annahme, die erstmal ungünstig ist und
wir werden auch noch sehen, wie wir die wieder loswerden.
Die können wir nämlich loswerden, indem wir selber im Algorithmus
dafür sorgen, dass die Eingabe tatsächlich gleich verteilt ist
Also wir überlassen das nicht dem Benutzer,
der irgendwie diese Zahlenfolge eingeht, weil da wissen wir,
das hängt von der Anwendung ab und das kann schon sein,
dass vielleicht eine fast sortierte Folge viel häufiger vorkommt,
wie eine komplett unsortierte Folge.
Könnte ja sein. Also wir überlassen das nicht
dem Benutzer, sondern wir machen das selber.
Wir sorgen im Algorithmus dafür, dass wir diese Gleichverteilung erreichen.
Und das ist immer genau der Schritt,
wo diese Randomisierung jetzt greift, wo wir die nutzen.
Okay, wenn wir randomisieren, brauchen wir
einen Zufallszahlengenerator
Der ist bei mir hier versteckt in so einer Funktion,
die heißt einfach nur random. Und die hat zwei Werte,
I und J, zwei Parameter,
E und J. Und unser Zufallszahlen-Generator liefert uns einfach eine Zahl.
K zwischen I und J, ja,
inklusive I und J, diese Werte darf das auch einnehmen.
Und zwar ist das ein ganz toller Zufallszahlen-Generator, der liefert Ergebnisse gleich verteilt.
Also das sollte ja ein Zufallsgenerator eigentlich machen,
der sollte dafür sorgen, dass jede Zahl in dem Zahlenintervall
mit gleicher Wahrscheinlichkeit vorkommt.
Nur das wäre ein
wirklich guter Zufallszahlen-Generator
Und davon gehen wir jetzt mal aus, dass das so ist.
Also die Wahrscheinlichkeit, dass unsere Random-Funktion, den Wert Chaos gibt,
ist gerade null. Wenn das K außerhalb des Intervalls liegt,
also wenn Karl kleiner ist als IE oder Karl größer ist als J.
Und die Wahrscheinlichkeit ist eins durch J-I plus 1
für den Fall, dass K in dem Intervall liegt.
Und J minus i plus 1 ist die Anzahl der Werte,
die wir in dem Intervall haben.
Und ja, wenn davon jeder gleich wahrscheinlich ist,
dann ist das hier entsprechend das genau die Wahrscheinlichkeit,
die dann übrig bleibt für jeden der einzelnen Fälle.
Also eins durch J minus i plus
Okay, so, den Zufallzahlen-Generator, den werden wir jetzt
verwenden in unserer Funktion, die sequenziell das Optimum sucht.
Ziel ist es, den so einzusetzen, dass die Bearbeitungsreihenfolge unabhängig wird von dem,
was der Benutzer getan hat. Und das machen wir,
indem wir hier in dieser Vorschleife einfach in dem Array mal Daten vertauschen,
ja, was wir vertauschen ist,
wir wenden unseren Zufallzahlen-Generator an in dem Intervall von I bis N,
ja, und dann vertauschen wir das Array-Element A aus diesem Bereich mit dem Element AI.
Und AI ist das Element, was wir dann in dieser
Iteration betrachten. Sie können sich das auch so vorstellen,
dass wir einfach aus der Menge der noch verbleibenden Zahlen,
in dem Array, die wir noch nicht betrachtet haben,
zufällig die nächste Zahl auswählen.
Und das ändert sozusagen dem Okalkül die Laufzeit des Algorithmus erstmal nicht,
weil wir davon ausgehen, der random der Zufallzahlengenerator hier,
der braucht konstante Zeit, um uns eine Zufallzahl zu liefern.
Und diese Swap-Operation, die vertauscht zwei Elemente in einem Array,
Das ist auch konstante Zeit. Deswegen ist es erstmal im
Orkalkühl nicht relevant, dass wir diese Zeile hier eingefügt haben.
Und auch für die Worst-Case-Analyse macht diese Zeile keinen Unterschied.
Im Worst-Case ist es natürlich immer noch so,
dass die Laufzeit dieser Funktion N plus,
also O von N plus N mal C, DSE,
also do something expensive here, ist,
weil auch der Zufallzahlengenerator natürlich eine Folge von Zufallszahlen produzieren kann,
die dazu führt,
dass die Bearbeitungsfolge von dem AI hier aufsteigend sortiert ist
Ja, kann einfach sein, ist Pech. Ist auch
genauso wahrscheinlich wie vorher. Es ist eben eine der möglichen Endfakultät
vielen Folgen, wo diese Reihung aufsteigend sortiert ist. Okay,
da macht es also nichts,
aber für uns hat es jetzt einen ganz großen Gewinn,
weil wir durch diesen Schritt, den wir hier eingefügt haben,
ist die Bearbeitungsreihenfolge unabhängig von dem, was der Benutzer getan hat.
Okay, also, jetzt machen wir die Average Case Analyse.
Wir können jetzt davon ausgehen, dass in diesem Schritt hier die,
also in diesem Schritt quasi die Daten tatsächlich zufällig verteilt sind
Ja. Und können jetzt anfangen und uns überlegen, wie lange dauert das?
So, wie machen wir das? Also ich habe gesagt,
normalerweise müssen wir mitteln über alle möglichen Eingaben oder über alle
möglichen Folgen dieser, dieses Zufallszahlengenerators in diesem Fall.
Das wäre extrem aufwendig. Da muss man sich die alle
überlegen und so. So machen wir das nicht.
Das wäre nicht so schön. Was wir machen ist,
wir werden uns Entscheidungen in dem Algorithmus anschauen, die von einem Zufallsprozess abhängen.
Und genau die werden wir charakterisieren und dann werden wir die
Mechanismen aus der Storastik, also die Erbrechnung der Erwartungswerte einsetzen.
Und so ein Erwartungswert ist ja quasi nichts anderes als
quasi einen mit der Wahrscheinlichkeit gemittelter Ausgangswert einer Funktion.
Gut, also diese Indikatorfunktion beschreiben wir uns immer nur binäre Ereignisse.
Also ein Indikatorfunktion können Sie sich vorstellen, wie eine Bedingung in einem If-Statement.
Und das ist entweder wahr oder es ist falsch.
Ja, es gibt nur die beiden Optionen. Und damit
beschreiben wir ein Ereignis A. Und dieses Ereignis A kann eintreten,
dann ist diese Indikatorfunktion 1 oder dieses Ereignis kann nicht eintreten,
dann ist die Indikatorfunktion null
So, dann ist natürlich erstmal die Frage,
was hat diese so eine Funktion für einen Erwartungswert?
Das kann man ganz leicht berechnen. Also Erwartungswert ist ja nichts weiter
als die Summe über alle möglichen Fälle, die rauskommen können,
wo wir dann den Wert für diesen Fall multiplizieren mit der Wahrscheinlichkeit,
dass der Fall eintritt.
Das machen wir hier auch. Es gibt nur zwei Fälle,
entweder das Ereignis tritt ein und das Ereignis tritt nicht ein.
Das Ereignis heißt jetzt hier X, das ist das Gleiche
wie das hier. Also wir haben den Erwartungswert von
der Indikator-Funktion
Also abhängig von dem Ereignis X. Und das ist dann die
Indikatorfunktion für den Fall, dass X gleich 1 ist.
Das ist Ereignis Eintritt. Das ist ja eins.
Dann kriegt die Funktion den Wert 1. Mal die Wahrscheinlichkeit,
dass X-Eintritt plus die Indikatorfunktion für den Fall,
dass das Ereignis nicht eintritt.
Das ist dann null. Mal die Wahrscheinlichkeit, dass eben X nicht eintritt.
Und weil das hier ein nulles fällt, der Teil weg.
Und das ist eins, also was hier überrecht bleibt,
ist die Wahrscheinlichkeit, dass X eintritt.
Also der Erwartungswert für seine Indikatorfunktion ist nichts weiter als die Wahrscheinlichkeit,
dass der Fall, den wir hier beschreiben,
eintritt.
Das ist ganz einfach
Gut, den Erwartungswert werden wir jetzt berechnen und wenn wir
den Erwartungswert der Laufzeitfunktionen berechnen, kriegen wir die erwartete Laufzeit oder Speicherbedarf,
wenn sie so wollen.
Und damit beschreiben wir quasi die Laufzeit,
die wir quasi im mittleren Fall für den Algorithmus erhalten werden.
Wir werden also jetzt den Algorithmus nehmen,
wir werden ihn an gezielten Stellen durch diese Indikatorfunktionen beschreiben und
dann den Erwartungswert berechnen
Gut, wie kann man das jetzt machen?
Also das Schwierige ist jetzt so ein bisschen drüber nachzudenken,
wie wollen wir das modellieren mit den Indikatorfunktionen,
wenn man die dann erstmal da hat,
dann ist es nur ein bisschen umformulieren und dann hat man
dann das Ergebnis da schon stehen.
Was ist das Entscheidende Ereignis, was dazu führt,
dass unsere Laufzeit groß oder klein ist?
Das Entscheidende Ereignis in unserem Algorithmus ist diese IF-Anweisung hier.
Die habe ich hier mit so einem Sternchen markiert.
Wenn diese IF-Anweisung wahr ist, dann wächst unsere Laufzeit,
weil wir diese sehr teure Funktion ausführen müssen
Wenn die IF-Anweisungen, also die Bedingungen der Evanweisung falsch ist,
dann passiert das entsportlich nicht. Also, und ob das
hier wahr oder falsch ist, hängt quasi, naja,
von unserem Zufallzahlengenerator ab, der das AI ausgewählt hat.
Also ist das genau die Stelle, die wir durch diese Indikatorfunktion beschreiben werden. Gut,
wir sagen jetzt also,
wir haben jetzt also das Ereignis XI und das ist beschrieben,
nicht eine Indikatorfunktion und die Indikatorfunktion beschreibt,
ob AI zum Zeitpunkt Sternchen,
also in dem Algorithmus an der Stelle,
wo die IF-Anweisung ist,
optimal ist
Und diese Indikatorfunktion ist eben eins, wenn das wahr ist,
also AI ist zum Zeitpunkt Stern optimal. Das heißt,
die Bedingung ist wahr und die IF-Anweisung wird,
also wir gehen in den Blog der IF-Anweisung,
wir führen also die aufwendige Funktion aus und null sonst.
Okay, so, jetzt müssen wir uns als erstes überlegen,
wie hoch ist denn die Wahrscheinlichkeit, dass XE eintritt?
Ja, wir haben, wenn XEs,
also das Itemal, dass wir diese Entscheidung fällen,
zu dem Zeitpunkt haben wir schon einen gewissen Teil des ARS
betrachtet,
und zwar eh viele Werte
Wenn Sie sich vorstellen, Sie haben eine lange Liste von Zahlen.
Und Sie gucken sich nur die letzte Zahl an.
Das ist hier das A von I. Und hier haben Sie I
minus eins andere Zahlen stehen. Dann fragen Sie sich,
wie wahrscheinlich ist es, dass das hier das Maximum ist?
Und das kann man ganz leicht ausrechnen, weil,
naja, Sie haben hier I-Positionen insgesamt.
Und Sie wissen nur an einer Position steht das Maximum.
Wir gehen davon aus, das Maximum ist eindeutig.
Also nur an einer Stelle ist das Maximum.
Und wenn wir Gleichverteilung annehmen können, können wir,
weil wir ja diese, weil wir unseren Randomisierer eingesetzt haben.
Wir wissen, jede Verteilung ist gleich wahrscheinlich. Naja,
dann ist die Situation,
dass genau hier das Maximum drin steht, eben genauso wahrscheinlich,
wie das hier das Maximum drinsteht oder hier oder hier oder hier oder hier, ja.
Und dementsprechend ist die Wahrscheinlichkeit dafür,
dass der Fall XI eintritt, nichts weiter als eins durch I.
Also jeder dieser I-Fälle ist gleichwahrscheinlich. Okay, damit können wir
jetzt die Laufzeit berechnen. Wir sagen einfach die Laufzeit,
die wir haben, für unsere Funktion, ist im Okalkül N,
also irgendwas proportional zu enden, brauchen wir auf alle Fälle.
Das brauchen wir, um die Vorschleife einfach auszuführen.
Und das ist irgendwie der Aufwand enden. Und dann haben
wir ja noch die sehr teure Funktion, do something expensive.
Und jetzt müssen wir wissen, wie häufig wird die ausgeführt.
Und das ist die erwartete Anzahl von Fällen,
in dem unsere Indikator Variable 1 wird.
Also immer, wenn die eins wird,
müssen wir in den Ausführungsblock hinein und müssen diese Funktion ausführen.
Okay, gut. Also N plus konstante CDSE mal Erwartungswert von,
haben, wir gehen durch das ganze Array durch,
also I gleich 1 bis N. Alle Positionen im Array XI.
Und das XI ist mal null und mal ist es eins.
Je nachdem, ob der If-Fall eintritt oder nicht eintritt.
Der Erwartungswert hat ein paar ganz tolle Eigenschaften, und zwar ist der linear.
Das heißt nichts weiter. Das steht hier im Kormen,
auch im Anhang, dass wenn sie sowas haben wie A X plus WB Y. Ja,
und sie haben zwei Variablen X und Y Wahrscheinlichkeiten,
dann können sie das einfach trennen und die Konstante daraus ziehen.
Dann haben sie eh von AX plus B von dem Erwartungswert von Y.
Und das Tolle beim Erwartungswert ist, das gilt sogar,
wenn X und Y nicht stochrastisch unabhängig voneinander sind.
Also bei der Varianz geht das nicht, aber im Erwartungswert geht das.
Also selbst wenn die was miteinander zu tun haben, dürfen sie das so trennen. Und das ist natürlich hervorragend,
das werden wir fast immer brauchen,
dass wir den Erwartungswert quasi bezüglich seiner Linearität zerlegen können Und hier bedeutet das nichts weiter,
als dass wir den Erwartungswert in die Summe reinziehen können und können dann sagen,
das ist das Gleiche wie N plus konstante Mal,
jetzt die Summe, I gleich 1 bis N,
Erwartungswert von XI.
Diesen Erwartungswert von XI, also den kennen wir schon,
denn wir wissen für diese einfachen Indikatorfunktionen ist der Erwartungswert genauso
groß wie die Wahrscheinlichkeit, dass das Ereignis eintritt.
Das hatten wir hier gerade gesehen. Also der Erwartungswert hier
ist nichts weiter als eins durch I. Also die Wahrscheinlichkeit,
dass das Ereignis eintritt. Dann haben wir jetzt also hier die Summe,
I gleich 1 bis N, 1 durch I,
das ist die Summe über die Brüche, Bruchfolge,
wenn sie sie wollen, also eins plus eineinhalb,
plus ein Drittel plus ein Viertel und so, weiter.
Und die Folge, es hat auch einen Namen,
ist die harmonische Reihe. Und von der weiß man,
dass diese Summe hier beschränkt ist durch den natürlichen Logorithmus von N.
Die Herleitung davon sehen Sie im Callment-Anhang oder auch in dem Mathe-Anhang
zum Skript. Ja, da steht das auch nochmal drin.
An dieser Stelle würde ich das nicht machen.
Also es ist nur einfach der Hinweis,
Summe über die Brüche kann man immer abschätzen durch den Logorithmus
Okay, und damit haben wir eine Schranke für den mittleren Fall,
also O von N plus CDSE, mal LNN plus C. Konstanten,
die können wir dann hier rausfallen lassen,
weil die natürlich vom Wachstum her ist,
die Konstante C ist vom Wachstum kleiner als LNN.
Ja, und dann hätten wir eine neue Betrachtung.
Und die ist substanziell besser als die,
die wir bisher gesehen haben. Unsere Worst-Case-Betrachtung hatte eine,
hatte hier ein N-Mahl, diese Konstante CDSE.
Jetzt ist es
nur noch lugorithmisch
Ein. Es ist also eine gute Erkenntnis,
die wir gewonnen haben, also die mittlere Laufzeit ist,
wie erwartet, viel geringer als der Worst Case, der eingetreten ist.
Und wir können sogar genau sagen, wie gering es ist.
Also wir haben hier eine gute Abschätzung gefunden und gesehen,
dass genau dieser Fall eben nur luggerithmisch mal eintritt.
Okay, und die Analyse ist auch nicht so schwierig.
Also wir müssen eigentlich immer nur gucken, wo sind so die Stellen,
wo vom Zufall beeinflusste Entscheidungen fallen, die laufzeitrelevant sind.
Da setzen wir eine Indikatorfunktion ein wenn wir das gemacht haben,
nutzen wir die Linearität des Erwartungswerts,
können dann die Gleichung vereinfachen und dann können wir entsprechend in der Regel das auflösen und kriegen eine mittlere Laufzeit.
Und wenn Sie mal jetzt noch mal darüber nachdenken,
mit was für einen Anspruch wir gestartet sind,
nämlich zu sagen, wir wollen die mittlere Laufzeit berechnen,
dazu müssten wir ja jede mögliche Eingabefolge analysieren und dann die Laufzeit darüber mitteln,
dann ist das natürlich hier viel, viel einfacher.
Also denken Sie nur über den Aufwand nach,
tatsächlich sich Gedanken zu machen, wie häufig was passiert,
wenn Sie quasi über all diese Fälle mitteln würden
Geht auch, ja. Ich will nicht sagen, dass
es nicht machbar ist. Klar kann man das auch ausrechnen.
Aber das ist eben eine sehr flexible Art und Weise, diese Analyse durchzuführen.
Okay, so. Was wir jetzt noch zeigen müssen,
ist, dass wir mit unserer Technik, dass wir so
ein Element einfach vertauschen, tatsächlich eine zufällige Reihenfolge bekommen.
Das habe ich immer jetzt die ganze Zeit so behauptet.
Aber das ist, müssen wir erstmal noch nachweisen,
dass das tatsächlich so ist. Also was wir ja tun,
ist, wir sagen, die wählen immer aus allen verbleibenden Zahlen.
Wir haben also das Array, das hat irgendeinen speziellen Zustand
und zum Zeitpunkt I haben wir also einige Elemente schon ausgewählt.
Und mit der Random-Funktion suchen wir uns willkürlich irgendeines der Elemente
hier aus und schreiben es quasi hier an die nächste Position.
Das ist das Verfahren, was wir betreiben. Und jetzt müssen wir noch zeigen,
dass angenommen, dass diese Random-Funktion hier tatsächlich,
also die muss gleich verteilt sein, sonst funktioniert es natürlich nicht,
aber angenommen, die ist gleich verteilt,
dass wir dann wirklich eine beliebige,
zufällige Reihenfolge der Eingabe bekommen
Ja. Dieses Verfahren, was wir hier sehen, das heißt,
randomize and place, also wir nehmen ja das Array,
wir verwenden den Speicherplatz, das Arrays und randomisieren da drin,
indem wir dann Datenelemente vertauschen.
Und das ist hier einfach nur noch mal zusammengefasst.
Randomize and place für ein RAR mit N-Elementen,
macht es nichts weißer als eine Vorschleife,
die Wolf von 1 bis N minus 1 und vertauscht das
IT-Element mit einem zufällig ausgewählten Element aus dem Intervall von I bis N.
Beachten Sie, dass das auch das IT-Element
selber sein kann
Also was dann da bedeuten würde, dass nichts vertauscht wird.
Aber den Fall müssen wir zulassen hier. Okay,
so, wie können wir jetzt sehen, dass diese Funktion
hier tatsächlich eine zufällige Reihenfolge in dem Array produzieren kann?
Das ist ein bisschen tricky. Was wir machen ist,
wir müssen erstmal überlegen, ja, wie viele Möglichkeiten gibt es denn jetzt hier?
Ja, wie viele Möglichkeiten gibt es Endzahlen, eine beliebige Ordnung zu bringen?
Da gibt es Endfakultät, viele Ordnungen. Das heißt,
wir müssen ihr zeigen, dass jede Folge von Zahlen,
die vorkommen kann, mit gleicher Wahrscheinlichkeit, nämlich eins durch ein Fakultät auftritt.
Okay, dafür müssen wir ein bisschen rechnen. Wir brauchen uns
das erste Mal den Begriff der K-Per-Mutation, Caprian-Mutation besagt,
dass wir einfach eine Permutation von Chaos-N-Werten haben. Also wir haben hier N-Werte,
das ist unser ganzes Array, wenn sie so wollen,
und dann nehmen wir einen Teil davon raus, nämlich K,
viele von diesen Werten, und dann schauen wir uns an, wie viele mögliche Reihenfolgen gibt es davon.
Und das kann man ganz leicht berechnen. Also wenn sie jetzt K-Werte aus N herausnehmen,
das ist übrigens das, was sie beim Lotto-Spielen auch immer haben,
da haben sie auch Car-Permutation, da wählen sie sieben aus 49 Kugeln aus,
und die bringen sie Naja, die bringen sie nicht in eine beliebige Reihenfolge,
die sortieren sie ja aufsteigend, aber zumindest die Kugeln,
wenn sie die betrachten, in der Reihenfolge,
in der sie aus dem Automaten rausfallen,
haben sie auch eine Carper-Motation.
Okay, ja, wie viele Möglichkeiten gibt es da?
Das ist ganz einfach für die erste Kugel, haben sie N-Möglichkeiten?
Ja, für die nächste haben sie dann noch N-minus eins Möglichkeiten,
für die nächste N-minus zwei und so weiter.
Und das ist dann also nichts weiter als N,
mal N-minus eins und so weiter, bis N-minus Carplus 1,
was wir multiplizieren müssen, um diese Anzahl zu bestimmen.
Können wir auch durch die Fakultät ausdrücken?
Das wäre dann Endfakultät durch N-minus-K-Fakultät
So, auf der Basis können wir jetzt zeigen,
es ist dieses Lämmer hier, dass diese Randomisierungsfunktion,
randomized in place, tatsächlich eine zufällige Anordnung von Zahlen bestimmt.
Das machen wir durch eine Schleifeninnenvariante. Ja,
wir haben ja eine Schleife hier und wir müssen,
wir wollen zeigen, dass der Algorithmus korrekt ist.
Korrektheitsbeweis mit Schleifen, machen wir mit Schleifen in Variante.
Und als erstes müssen wir sagen, wie unsere Schleifen in Variante aussieht,
das ist hier eigentlich ganz einfach. Wir sagen nur,
dass der Algorithmus zu jedem Zeitpunkt, also zum Zeitpunkt I,
hat er ja bis zu einem zu einem speziellen Punkt schon sein Array festgelegt,
diesem vorderen Teil, ja, dann sagen wir nichts weiter,
als zum Zeitpunkt I wissen wir,
dass in diesem vorderen Teil schon eine zufällige Permutation drinsteht.
Und ja, wenn wir das Ganze dann machen bis zum Ende,
wenn die Schleife abgeschlossen ist, dann wissen wir,
dass in dem gesamten Array eine zufällige Permutation drinsteht.
Wir müssen also dann auch zeigen,
dass sie natürlich mit gleicher Wahrscheinlichkeit auftritt und die steht hier.
Also die Schleifenin-Variante ist dann vor der Iden-Iteration gilt.
Jede mögliche i-erste Permutation tritt in A von 1 bis i minus 1,
also in dem vorderen Bereich des das RASA,
was wir hier sehen, mit Wahrscheinlichkeit n-i-plus 1 Fakultät durch N-Fakultät auf.
Das ist sozusagen dann die Gleichverteilung. Das ist die Anzahl
der Möglichkeiten, die es hier entsprechend gibt.
Gut, wie macht man das? Also müssen wir zeigen,
dass diese Schleifeninnenvariante korrekt ist. Wir haben eine Initialisierung,
also vor dem Schleifendurchlauf gilt, da ist I gleich 1,
da haben wir noch nichts des Arrays gesehen.
Dann sind wir also an dieser Stelle und dann sehen wir,
wir haben das Array von 1 bis 0,
also irgendwie ein leeres Array und da gibt es keine alternativen Belegungen.
Wir haben eine Nullpermutation und da ist die Wahrscheinlichkeit,
dass die eintritt, weil es gar keine Alternativen gibt.
Eins, also es ist Endfakultät durch Endfakultät. So,
jetzt gehen wir von Schleifen von einem Schleifendurchlauf zum nächsten
und gucken uns die IT-Iteration an. In der IT-Iteration wissen wir,
dass wir schon in der I-minus ersten Iteration durch die Innenvariante
eine zufällige Verteilung der Daten haben.
Das heißt, Wir haben jetzt eine beliebige E-Per-Mutation,
also der von I-Zahlen aus allen möglichen Zahlen, die auftreten können.
Und damit die auftreten kann, müssen wir vorher eine beliebige E-Minus-1-Per-Mutation haben.
In dem vorderen Teil des Aris von E von 1
bis i minus 1. Also bis hierhin,
hier ist das i minus 1, ist der Teil,
der quasi in der vorherigen Iteration betrachtet wurde.
Und damit dann genau diese Per-Mutation auftritt,
müssen wir dann in der Iden-Iteration dieses Element AI auswählen.
Das muss immer ein Bild hier ein bisschen anpassen.
Und an diese Stelle
hier kopieren
Und dann haben wir genau diese spezielle Folge. So,
wie wahrscheinlich ist, dass diese spezielle Folge von Zahlen von 1 bis i auftritt?
Wir haben hier zwei Ereignisse. Das erste Ereignis,
das nenne ich mal E1, das erste Ereignis ist,
dass in dem vorderen Teil des Airrays bereizt diese Permutation 1
bis i minus 1 drinsteht.
Und dann haben wir das Ereignis E2 und das Ereignis besagt,
dass wir in der Eaten-Iteration genau dieses Element AI auswählen und an diese Stelle hinkopieren.
Und dann kriegen wir die vorgegebene Folge von 1 bis
Ja. So, wie ist die,
hoch ist die Wahrscheinlichkeit, dass beides eintritt?
Also beides muss ja eintritten, damit wir diese Folge haben.
Also E2 und E1 müssen eintreten. E2 muss eintreten unter der Annahme,
dass vorher R-E-1 aufgetreten ist, weil das passiert ja vorher.
Und ja, dann wissen wir, ja,
wir haben hier noch ein paar Elemente übrig.
Das sind nämlich n-i-i plus 1 viele Elemente, die wir haben.
Und aus denen wählen wir zufällig eins aus. Und damit
wir genau dieses eine Element, was wir haben wollen,
auswählen,
ist die Wahrscheinlichkeit
Bei Gleichverteilung, des Zufallszahlengenerators, eins durch N-E-Plus 1. So,
und die Schleifen in Variante sagt uns, dass die Wahrscheinlichkeit,
dass die Folge A von 1 bis I minus 1 auftritt,
gerade N minus i plus 1 Fakultät durch N-Fakultät ist.
Das können wir jetzt multiplizieren,
dann kommt da N minus i-fakuliert durch N-Fakultät raus und das
ist genau die Schleifen in Variante nach der nächsten Iteration.
Und dann können wir zeigen, dass nach der,
wenn die Schleife beendet ist,
wenn I gleich N ist und dann können wir hier in
unserer Gleichung das N für I einsetzen und dann steht hier
N minus N plus 1 fakultiert durch N-Fakultät,
macht eins durch Infakultät
Okay, das war der Vollständigkeit halber nötig, um zu zeigen,
dass der Algorithmus wirklich funktioniert. Wir mussten einmal zeigen,
dass Randomized in Place wirklich eine beliebige Folge erzeugen kann.
Es sollte unserer Intuition entsprechen, dass ein solches Verfahren,
was ein beliebiges Element aussieht und an diese Stelle kopiert,
wirklich eine zufällige Folge eigentlich auch produziert.
Ja, das ist einfach nur nochmal nachgerechnet,
dass das tatsächlich auch so ist. So,
im Folgenden habe ich jetzt ein paar Beispiele für Sie,
wie die Integratorfunktion eingesetzt wird.
Ich werde das jetzt noch nicht so in Algorithmen einbetten
Und einfach nur mal Szenarien aufzeigen, die wir aber
in Algorithmen haben. Und eins dieser Szenarien kennt man unter
dem Begriff des Geburtstagsparadoxons, schon mal gehört.
Ja. Wie viele Personen braucht man in einem Raum,
damit die Wahrscheinlichkeit, dass zwei am gleichen Tag Geburtstag haben,
mindestens 50 Prozent ist,
das ist die exakte Frage beim Geburtstagsparadoxon?
Weiß es eine
25? 23, ne? Genau. Und das heißt,
nur deswegen Geburtstagsparadoxon,
weil wenn sie auf die Straße gehen und eine Befragung machen,
das ist nicht paradox im mathematischen Sinne, das ist ganz exakt,
aber wenn sie auf die Straße gehen und sie würden Leute befragen und sagen,
wie viele braucht man, dann liegt der Wert statistisch ein Faktor,
10 höher.
Ja, also die Schätzung liegt dann eher so bei 200 als bei 23.
Und das ist sozusagen, es ist sozusagen für unser Gefühl,
für unser Zahlengefühl ist es eigentlich viel unwahrscheinlicher,
dass zwei Personen am gleichen Tag Geburtstag haben
Und deswegen heißt das halt Geburtstagsparadoxon. Ja, es hört
sich jetzt erstmal nur nach so einer netten Partyspielerei an.
Aber das ist in der Informatik tatsächlich extrem wichtig.
Das Geburtstagsparadoxon. Und zwar, weil wir im Datenmanagement sehr viel mit Hashing arbeiten.
Herrsching haben Sie bestimmt alle schon mal gehört. Hashing-Techniken,
wenn wir Daten ablegen nach Schlüssel und die wiederfinden müssen.
Eine ganz zentrale Aufgabe in der Algorithmik, in den Datenbanken etc.,
dann haben wir immer da diesen unangenehmen Augenblick, Kollision haben.
Also zwei, die Hash-Funktionen legt zwei Datenwerte, die eigentlich
unterschiedlich sind, in das gleiche Datenfeld der Hash-Tabelle rein.
Und dann ist es immer, das ist immer der Teil,
der blöd ist am Hashing.
Da muss man sich was überlegen. Entweder verkettet man die oder
man hat offene Adressierung oder irgendwas, um diesen Fall aufzulösen.
Deswegen ist es natürlich ganz entscheidend herauszufinden,
wie häufig treten diese Kollisionen beim Hashing eigentlich auf.
Und das ist genauso wie mit dem Geburtstag.
Sie haben eine Menge von Zahlen und sie fragen,
wie groß ist die Wahrscheinlichkeit?
Das ist eine Menge von Zahlen. Zwei sind die zufälligerweise
genau an der gleichen Position der Hash-Tabelle
sitzen wollen
Okay, so, wir werden die Analyse hier mit der Indikator-Funktion
machen und wir werden jetzt gleich auch nicht die 23 sehen,
weil wir die Frage etwas anders formulieren als beim Geburtstagsparadoxern.
Unsere Frage ist die folgende. Wir haben also K-Ereignisse,
die treten also gleich verteilt auf.
Und zwar an einen von Endzeitpunkten. Und wie hoch ist
dann die erwartete Anzahl von Paaren gleichzeitig auftretende Ereignisse?
Also Sie können das, wenn Sie jetzt auf Hashing übertragen,
dann wären das jetzt nicht Zeitpunkte,
sondern Speicherplätze in der Hashtag-Welle
Okay, weil wenn wir jetzt eine Laufzeitanalyse machen würden
beim Hashing und würden nicht den Worst Case annehmen,
sondern wir würden uns überlegen, der hohe Aufwand tritt immer dann ein,
wenn wir eine Kollision haben bei den Daten,
dann müssten wir herausfinden, wie häufig tritt diese Kollision auf.
Genauso wie bei unserem Randomized Select Opt,
wo wir immer herausfinden müssen, wie häufig tritt dieser Fall auf,
dass wir das Optimum finden.
Müssen wir herausfinden, wie häufig tritt die Situation einer Kollision auf?
Okay, wie kann man das mit Indikatorfunktionen modellieren?
Das machen wir wie folgt. Wir definieren das Ereignis,
das I und J, also wir haben jetzt diese Folge
von K-Ereignissen, das I und J gleichzeitig auftreten.
Das ist XIJ
Und das ist unser Indikator. Und der ist genau wie
vorher wieder so, es ist eine 0-1-Entscheidung.
Es ist die 0-1-Entscheidung, die von der Verteilung der Eingabedaten abhängt.
Also da kommt irgendwie der Input rein, ob der Input
gerade so ist, dass dieses Ereignis eintritt oder nicht.
Und es ist das Ereignis, was die Laufzeit entscheidend verändert.
Weil wenn so eine Kollision eintritt,
dann haben wir einen höheren Laufzeitbedarf, um die Kollision aufzulösen.
Okay, das ist also unsere Indikatorfunktion. Und dann können wir
sagen, gut, wie hoch ist der Erwartungswert dafür,
dass das Ereignis eintritt
Und dann sagen wir, okay, wir haben ja Endzeitpunkte,
die wir analysieren müssen. Das heißt, wir haben also
die Summe von K gleich 1 bis N, ja.
Und also, weil wir ja nicht wissen, welchen Zeitpunkt wir betrachten. Also,
dieses Ereignis, das I und J gleichzeitig auftreten kann,
kann ja zum Zeitpunkt 1, zum Zeitpunkt 5, zum Zeitpunkt 20 auftreten.
Summieren wir also über alle Zeitpunkte und naja,
dann haben wir die Wahrscheinlichkeit,
dass das Ereignis I zum Zeitpunkt K eintritt und,
also multiplizieren müssen wir das, mit der Wahrscheinlichkeit,
dass das der eigenes J zum Zeitpunkt K eintritt.
Weil wenn die beide zum Zeitpunkt K eintreten,
haben wir
gerade diese Kollision
Okay, wir gehen von Gleichverteilung der Daten aus.
Das heißt, die Wahrscheinlichkeit, dass I zu einem speziellen
Zeitpunkt K auftritt, ist nichts weiter als eins durch N.
Wir haben Endzeitpunkte, die sind alle gleich wahrscheinlich.
Und dann haben wir also hier eins durch N.
Wir gehen auch von Unabhängigkeit heraus. Das heißt,
das Ereignis I ist unabhängig von dem Ereignis J. Und dann haben wir hier eins durch N.
Und hier haben wir eins durch N. Macht also K gleich 1
bis N eins durch ein Mal 1 durch N. Ja,
und das ist also die Summe,
karg ich 1 bis N 1 durch N Quadrat.
Das haben wir also eng mal eins durch eng Quadrat,
macht also eins durch
Also die Erwartung, der Erwartungswert hier, entspricht ja der
Wahrscheinlichkeit für das Ereignis XEJ, beträgt dann eins durch N.
Das ist tatsächlich in der Zeit jetzt noch niedrig.
Es ist immer noch ein kleiner Wert, dass das tatsächlich eintritt.
Und darin liegt auch genau die Krux bei dem Geburtstagsparadoxum,
warum sich so viele vertun, weil sie eben übersehen,
dass es ja relativ viele Zeitpunkte gibt,
die man natürlich auch betrachtet, nämlich jeden möglichen Tag.
Und dass die Ideen eben nicht vorgeben. Also so gefühlt,
wenn wir sagen, wir reden von zwei Personen,
die am gleichen Tag Geburtstag haben, denkt man dann immer,
Aber wer heißt denn jetzt noch hier im Raum,
der am gleichen Tag Geburtstag hat wie ich?
Das ist ja viel unwahrscheinlicher, ja. Okay, so. So,
und jetzt müssen wir natürlich nicht nur berechnen,
wie groß ist die Wahrscheinlichkeit oder die erwartete Anzahl oder wie groß
ist die Wahrscheinlichkeit für das Ereignis, dass I und J gleichzeitig auftreten,
sondern wir müssen ja die ganze Menge betrachten von unseren K-Ereignissen,
ja, hier.
Und deswegen berechnen wir jetzt, haben wir eine Variable X,
die beschreibt die Anzahl der Paare, der gleichzeitig auftretenden Ereignisse
Ja, das ist dann. Und dann müssen wir davon
den Erwartungswert berechnen. Und das dominiert dann entsprechend die Laufzeit.
Für diese Anzahl Paare müssen wir in diesem Hashing-Verfahren Alternativen finden.
Also eine alternative Position finden, den höheren Aufwand produzieren.
Okay, da müssen wir nichts weiter tun,
als alle möglichen Kombinationen von Paare durchprobieren. Das heißt,
wir haben die Summe von Igarch 1 bis K und von J
gleich I plus 1 bis K. Das könnte auch bis K minus 1 laufen hier,
aber es ist irrelevant.
Und dann die Wahrscheinlichkeit,
dass XIJ gleichzeitig auftritt
Ja, und da wissen wir, die Wahrscheinlichkeit entspricht dem Erwartungswert.
Wir haben die Linearität des Erwartungswertes hier wieder.
Die Summe können wir den Erwartungswert da reinziehen. Den Erwartungswert,
den kennen wir, das ist ja eins durch N,
den haben wir gerade ausgerechnet.
Und dann haben wir hier nur eine Konstante und da müssen
wir nur gucken, wie viele Seumanten gibt es hier.
Das ist ja nichts weiter, als wie viele Paarkombinationen gibt es zwischen den beiden.
Und das sind ka, mal k-minus eins, halbe viele.
Dann haben wir also Karmakam minus eins, halbe Mal eins
durch N. Okay, damit sind wir eigentlich soweit fertig.
Hiermit kennen wir die erwartete Anzahl von Kollisionen für den Fall,
dass wir K-Datentabelle, äh, Datenelemente in eine Hash-Tabelle mit N-Datenpunkte einfügen wollen.
Oder die Anzahl der erwarteten Kollisionen für den Fall,
dass K-Ereignisse da sind und die gleichzeitig bei N-Ereignissen auftreten.
Ja, Scheduling ist übrigens ein anderes Beispiel, wo das auftritt.
Da haben sie tatsächlich Zeitpunkte, wo sie dann hier diese Fragestellung haben. So,
und dann, ja, können wir natürlich das auch mal umformen,
spaßeshalber und können sagen,
okay, wenn wir das jetzt mal nach K auflösen,
haben wir eine einfache quadratische Gleichung und würden sagen,
wann ist denn der Erwartungswert größer gleich eins
Der ist genau dann größer, gleich eins,
wenn K. größer gleich ein Halb plus Wurzel,
ein Viertel plus zwei N ist.
Das ist nichts weiter als die quadratische Gleichung von K.
hier aufgelöst. Okay, das kommt da raus.
Und jetzt können wir mal die Zahlen einsetzen vom Geburtstagsparadoxern.
Da hätten wir ja K-Leute auf der Party und 365 Tage im Jahr.
Da wäre N also 365 und wir würden sagen,
wie hoch ist die erwartete Anzahl von Paaren,
die gleichzeitig quasi am gleichen Tag Geburtstag haben.
Und wenn wir das hier einsetzen, kommt da ungefähr 27,5 raus.
K ist also größer gleich 27,5. Das sind nicht die 23
von Geburtstagsparadoxon, ist aber auch ganz leicht zu erklären,
weil die Frage beim Geburtstagsparadoxon ist ja ein bisschen anders.
Da fragen wir, wie viele Leute müssen im Raum sein,
sodass die Wahrscheinlichkeit, dass so eine Kollision auftritt größer gleich 50 Prozent ist.
Hier haben wir jetzt das mindestens eine Kollision auftritt.
Und selbst wenn man hier 50 Prozent einsetzt,
ist es noch nicht das Gleiche,
weil dieser Erwartungswert hier umfasst ja eben auch die Möglichkeit,
Dass vier Leute an zwei unterschiedlichen Zeitpunkten zum gleichen Zeitgeburtstag haben.
Wir zählen ja die Anzahl der Kollisionen.
Wir sagen nicht nur, es tritt eine Kollision auf.
Und deswegen ist die Herleitung ein bisschen anders, als sie vom Geburtstagsparadoxon.
Aber die beiden Probleme sind halt sehr miteinander verwandt. Und das,
was uns interessiert, um Laufzeiten zu berechnen, ist eben dieses E-Phone X.
Also tatsächlich, wie häufig haben wir diesen Fall, dass
die Kollision auftritt? Okay, das ist ein schönes Beispiel,
wie man das einsetzen kann, wenn man Kollisionen hat.
Ich habe noch ein zweites Beispiel für Sie
Was auch in der Informatik ganz wichtig ist.
Wir haben Ereignisse, die der Reihe nach auftreten.
Und jedes dieser Ereignisse kann ein von B vielen Fällen auf einnehmen.
Also ganz einfach können sie sich das vorstellen mit einem Würfel.
Also sie haben Würfel, da haben sie dann sechs mögliche Fälle.
Und sie würfeln. Und das Ereignis ist, dass sie einmal gewürfelt haben.
Und dann ist das Ergebnis ist einer von sechs Fällen,
nämlich die Zahl, die sie geworfen haben.
Eins, zwei, drei, vier, fünf, sechs.
Und was uns jetzt interessiert, ist,
wie hoch ist die erwartete Anzahl von Ereignissen
Bei N. Bis jeder, der B-Fälle mindestens einmal aufgetreten ist.
Warum ist das eine wichtige Fragestellung? Es kommt auch in
der Algorithmik vor. Zum Beispiel, wenn Sie sich fragen,
wenn Sie Testszenarien aufbauen für Algorithmen, dann wissen Sie,
Ihr Algorithmus hat vielleicht b viele Sonderfälle, die auftreten.
Und Sie wissen,
Sie machen einen Testexperiment mit Eingabedaten und Sie fragen sich einfach,
wie viele Tests müssen Sie durchführen,
bis Sie erwartungsgemäß jeden dieser B-Fälle
einmal gesehen haben
Okay, das wäre die Frage, die man sich stellt.
Und das ist jetzt von der Modellierung ein klein bisschen komplizierter.
Wir müssen jetzt erst mal überlegen, was passiert jetzt?
Also ich mache das mal wieder mit einem Würfel,
das kann man sich ganz gut vorstellen.
Und hier sehen Sie mal eine Sequenz von Würfen mit einem Würfel.
Das sind alles Zahlen von drei bis sechs, habe ich das einfach so hingeschrieben.
Das heißt, jemand hat erst eine Drei gewürfelt,
dann eine Eins, dann geht dann wieder drei,
eine zwei, eine vier, eine Drei und so weiter.
Und jetzt ist es natürlich so, dass am Anfang es ist ganz häufig so,
dass eine Zahl gewürfelt wird, die wir vorher noch nicht gesehen haben.
Also beim ersten Mal haben wir garantiert eine Zahl,
die wir vorher nicht gesehen haben, egal was wir werfen.
Beim zweiten Mal könnte es natürlich jetzt sein,
dass wir nochmal eine 3 geworfen hätten, aber die Wahrscheinlichkeit,
dass wir was anderes werfen, ist relativ hoch.
Also wir werfen jetzt hier eine 1. So, und die Wahrscheinlichkeit,
dass wir was Neues sehen, die singt mit der Zeit,
ja, weil wir immer mehr Zahlen schon gesehen haben und es bleiben immer weniger Zahlen übrig, die wir noch nicht entdeckt haben, also die noch nicht geworfen wurden. Und das sieht man hier auch schon,
also es ist, wie gesagt, natürlich ein Zufallsprozess,
das kann immer mal so und mal so ausgehen,
aber dann haben sie hier dann, also hier wäre die Folge 3,
1, dann hätten wir schon zwei Zahlen gesehen,
dann würden wir die drei wiederwerfen,
haben wir immer noch nur zwei Zahlen gesehen und dann würden wir die zwei würfen und dann haben wir die dritte Zahl gesehen,
ja, dann würden wir vielleicht die vier würfeln,
dann haben wir schon die vierte Zahl gesehen und dann müssen wir ein paar Mal würfeln,
bis wir das erste Mal die sechs sehen und dann hätten wir schon fünf Zahlen gesehen und dann brauchen wir noch eine ganz lange Folge,
bis wir die letzte Zahl, unsere fünf,
die ist hier hinter der Tafel,
bis wir dann die fünf Mal geworfen haben,
ja.
Okay, diesen Prozess müssen wir modellieren durch Indikatorfunktion
und da stellt sich natürlich auch wieder die Frage,
wie machen wir das und was sind die entscheidenden Ereignisse
Das entscheidende Ereignis ist, dass wir eine neue Zahl werfen.
Und dann wissen wir, das müssen wir genau K- oder EN-Mahl machen,
bis wir quasi jede Zahl einmal gesehen haben.
So, das modellieren wir und beschreiben als erstes mal die Wahrscheinlichkeit,
dass wir, wir teilen das in Abschnitte ein.
Und dann der IT-Abschnitt, der endet immer dann, wenn wir
die IT-Zahl gefunden haben. Also hier der erste Abschnitt,
der endet mit dem Finden der ersten Zahl.
Der zweite Abschnitt endet mit dem Finden der zweiten Zahl und
der dritte Abschnitt findet mit dem Fin,
endet mit dem Finden der dritten Zahl und so weiter
So, und dann ist eben die Frage,
wie groß ist die Wahrscheinlichkeit, dass wir so einen Abschnitt
quasi abschließen können, dass wir eine neue Zahl entdecken.
Und das beschreiben wir als die Wahrscheinlichkeit, dass wir von
dem Abschnitt I in den Abschnitt I plus 1 übergehen.
Und die Wahrscheinlichkeit ist ganz einfach zu berechnen.
Das ist nämlich nur, wir gehen wieder von Gleichverteilung aus.
Das ist eben nur die Wahrscheinlichkeit, dass wir noch eine neue Zahl entdecken.
Und das ist b-i plus 1 geteilt durch B. Können Sie einfach mal einsetzen,
wenn wir zum Beispiel hier in Abschnitt 5 wären,
dann hätten wir sechs, minus 5 plus Eins,
also zwei, geteilt durch sechs, also ein Drittel.
Also die Wahrscheinlichkeit, dass wir diesen Abschnitt verlassen, ist ein Drittel.
Das stimmt auch, weil wir entweder die fünf oder
die sechs werfen können, um den Abschnitt zu beenden.
Okay, das ist also die Wahrscheinlichkeit, dass wir so
einen Abschnittswechsel hinbekommen. Und dann wissen wir, naja,
wir müssen nacheinander sechs oder im Allgemeinen B viele Abschnittswechsel hinbekommen.
Und dann haben wir jedes Ereignis einmal gesehen.
So, wie groß ist die Anzahl der Erwarteten?
Die erwartete Anzahl von Ereignissen in dem Iden-Abschnitt.
Also wie häufig müssen wir werfen
Bis wir dann die neue Zahl entdecken. Dazu brauchen wir
tatsächlich jetzt die Stochastiker, die kennen das nämlich ziemlich gut.
Das ist nämlich eine Bekannte, eine sehr bekannte Verteilung von Daten.
Das ist hier diese geometrische Verteilung, die das beschreibt.
Und zwar die geometrische Verteilung haben wir immer dann,
wenn sie Ereignisse haben. Und sie können einen Erfolg oder
einen Misserfolg haben. Und sie fragen sich,
wie häufig müssen sie das wiederholen, bis sie einen Erfolg haben?
Können sie sich auch viele Beispiele für überlegen, dass das auftritt.
Das hat man auch ganz häufig in der Praxis.
Und da wissen wir schon, was für ein Erwartungswert da rauskommt.
Das hat man für diese Verteilung
schon berechnet
Das können wir gleich auch herleiten. Das ist ganz einfach
. Da kommt B durch b-i plus 1 raus.
Oder einfach nur der Kehrwert der Wahrscheinlichkeit hier.
So, okay. Und dann, ja, jetzt müssen wir
noch ausrechnen, wie lang diese Gesamtfolge ist. Ja,
das ist der Erwartungswert für die Folgenlänge des Abschnitts 1
plus der Erwartungswert für die Folgenlänge des Abschnitt 2 plus den
Erwartungswert für die Folgenlänge der Folge 3 und so weiter.
Das heißt, der Erwartungswert für die Länge der gesamten Folge
ist die Summe über die einzelnen Abschnittslängen.
Das ist hier NI. Und das geht von I
gleich 1 bis B, also wir haben B
verschiedene Werte
Und, ja, Linearität des Erwartungswertes macht Igarch 1
bis B, E von N.I. Das kennen wir,
können wir einsetzen, B durch B-I plus 1. So,
und jetzt haben wir hier so eine Summe.
Und wenn wir die Summe in der Summationsreihenfolge umdrehen,
dann ist das das Gleiche wie eins durch I.
Also B durch B-I plus 1, wenn man das aufsummiert,
ist das Gleiche, wie wenn wir die Werte von 1 bis I aufsummieren.
Also hier addieren Sie eins plus ein halb plus ein Drittel,
plus ein Viertel, plus ein 5 plus ein Sechstel.
Und hier addieren Sie ein 6 plus ein Fünftel,
plus ein Viertel, plus ein Drittel und so weiter.
Deswegen können wir das einfach umformen
Hier eins durch I. Und das hatten wir schon hier,
harmonische Reihe, Summe über die Brüche.
Und dann wissen wir, dass es in etwa so groß
wie der Logorithmus von B plus irgendeine kleine Konstante noch.
Ist auch ganz interessant. Gerade für die Brettspielstrategen, ja,
ist das eine nicht unerhebliche Zahl hier, wo sie herausfinden können,
ja, wie viele Würfe sie einfach brauchen,
bis sie alles mal einmal gesehen haben.
Es ist also einfach nur die Anzahl der Möglichkeiten,
die sie haben, multipliziert mit dem Logorithmus dieses Werts.
Ja, hier noch der Einschub zur, ich soll gerade mal gucken.
Also hier also der Einschub noch zur geometrischen Verteilung.
Warum kommt das da raus? Und was ist die geometrische Verteilung?
Also wir haben eine Sequenz von 0-1-Experimenten oder die Storastiker
nehmen meistens so Münzwurf mit Kopf und Zahl oder sowas für uns.
Also wie gesagt, 0-1-Experiment. Das Ereignis kann eintreten,
das kann nicht eintreten. Und sie haben eine Wahrscheinlichkeit P,
dafür, dass das Ereignis eintritt und eine Wahrscheinlichkeit Kuh,
dafür, dass das Ereignis nicht eintritt.
Kuh ist natürlich 1-P, weil es gibt nur diese
beiden Möglichkeiten
Und sie fragen sich, wie viele Versuche Ann sind notwendig,
bis das erste Mal unser Ereignis eintritt. Also das ist hier tatsächlich,
Mensch, ärgere dich nicht, wie häufig müssen sie würfeln,
bis sie die Sechs haben und rauskommen dürfen.
Und das können sie ausrechnen und die Wahrscheinlichkeit dafür,
dass sie Karma werfen müssen, die ist ja so groß
wie, sie haben Karminus-1-Misserfolge und dann einen Erfolg.
Das heißt, sie haben die Wahrscheinlichkeit Kuh,
das ist ja die Wahrscheinlichkeit für einen Misserfolg, hochkaminus-1,
malt P, das ist die Wahrscheinlichkeit für den Erfolg.
Und das ist genau diese geometrische Ja,
und dann kann man den Erwartungswert ausrechnen,
indem man sagt, ja, jetzt wollen wir wissen,
wie viele Würfe müssen wir denn oder können wir erwarten oder wie viele Versuche brauchen wir,
bis wir tatsächlich das Erfolgserlebnis hier haben.
Das wäre also eh von N der Erwartungswert von N.
Formel für den Erwartungswert ist eben die Anzahl der Würfe.
Mal die Wahrscheinlichkeit, dass wir so viel Würfe tatsächlich brauchen.
Und das geht von K gleich 1 bis unendlich,
weil wenn sie ein absoluter Pechvogel sind, brauchen sie halt verdammt lange.
Um diese spezielle Zahl zu bekommen, ja. Und da
können sie das jetzt einsetzen, die Wahrscheinlichkeit Wie hatten wir hier?
Das ist Kuhhochka-minus eins, mal P. Die Formel kann man jetzt vereinfachen,
da kann man P und Kuh rausziehen,
dann hat man die Summe vom K gleich eins bis zu unendlich,
Carv mal Kuhhochka.
Und dafür gibt es wiederum eine geschlossene Formel,
die steht hier unten, wie man darauf kommt.
Und wenn wir die mal einsetzen und das vereinfachen,
kommt eben eins durch P heraus. Und hier unten steht noch,
wie die geschlossene Formel abgeleitet werden kann,
für genau diese Folge von K mal xochka-1.
Das geht durch Differenzieren der geometrischen Reihe.
Aber das ist eben einfach nur eine Technik und das
ist einfach eine Formel,
die man
dann einsetzen kann
Okay, ein letztes Beispiel habe ich noch, das erkläre
ich Ihnen schon mal. Kurz, wie das funktioniert.
Wir haben eine Sequenz von 0-1-Ereignissen und wir fragen uns,
wie lang ist eigentlich die Teilsequenz oder von Einsen,
die wir da drin haben können.
Also eine zufällige Folge von Nullen und Eisen.
Und wie wahrscheinlich ist es, dass wir eine Folge von
K aufeinander folgenden Einsen haben.
Karma hintereinander Erfolg
Ja. Ja, auch dafür gibt es ganz viele Beispiele,
wo das in Algorithmen auftritt. Da kann ich Ihnen
eins liefern aus dem Bereich der Textsequenzen für die Bioinformatiker,
auch im Bereich der genomischen Sequenzen. Wenn Sie sich einfach fragen,
Sie haben zum Beispiel ein Stückchen Text und vergleichen das miteinander
mit einem anderen Text und Sie fragen, wie wahrscheinlich ist es,
dass Sie rein zufällig diesen Text wiederfinden?
Dieses eine Wort in einem langen Text wiederfinden.
Und unter der Annahme, dass die Zeichenfolgen zufällig sind,
könnten Sie das dann ausrechnen, indem die einfach sagen,
Sie haben einen Treffer oder keinen Treffer an einer Position
Und immer dann, wenn der Buchstabe übereinstimmt,
haben sie halt einen Treffer, dann haben sie ein Einsereignis.
Und wenn die Buchstaben dich übereinstimmen, haben sie ein Nullereignis.
Und wenn sie dann, meinetwegen, ein Wort haben mit
fünf Buchstaben, dann brauchen sie fünf aufeinanderfolgende Einzelereignisse.
Und dann hätten sie so eine entsprechende Sequenz. Genau,
das ist die erwartete Anzahl von solchen Teilsequenzen, von Einzelereignissen,
die uns interessieren. Okay, wie modelliert man das?
Wir haben wieder ein 0-1-Ereignis,
das 0-1-Ereignis besagt,
dass wir an der Position I eine Einsequenz
der Länge K haben
Und da wissen wir auch sofort, wie wahrscheinlich dieses Ereignis ist.
Das ist der Indikator hier. Das ist eine 0-1-Entscheidung.
Entweder wir haben da so eine Sequenz oder wir haben keine.
Und die Wahrscheinlichkeit können wir auch sagen,
weil wenn eine 0- und eine 1 gleich wahrscheinlich ist,
dann müssen wir ja kaum mal hintereinander eine 1 haben.
Das ist also ein Halbhoch K. Okay, das ist unsere Indikatorfunktion.
Und damit können wir jetzt sofort ausrechnen, was ist der
Erwartungswert dafür, dass wir seine Folge von K1 haben.
Naja, wir gehen jede Position in dieser Sequenz durch
Und schauen, dass ob wir da das Ereignis XIK haben.
Also ob wir an dieser Position eine Sequenz von K-Fielen einsen haben.
Das müssen wir nicht bis zum Ende der Sequenz machen,
sondern nur bis n-k plus 1, weil danach ist die
Sequenz nicht mehr lang genug, um K-1 zu haben.
Da ist die Wahrscheinlichkeit also null. Okay, der Erwartungswert
der Indikatorfunktion entspricht den Wahrscheinlichkeitswert, der Indikatorfunktion, das ist ein Halbhoch K.
Diese Summe ist nur eine begrenzte geometrische Reihe. Können wir,
nein, Entschuldigung, das sage ich jedes Mal der Stelle.
Hier haben wir ein Halbhoch K, das hängt nicht mehr
von I ab, können wir vor die Summe ziehen.
Das heißt, wir haben n-k plus 1 viele Semanten,
eins durch zwei OK, also durch zwei Hochkar.
Das ist das Ergebnis. Und jetzt können Sie einfach mal überlegen,
was kommt denn da raus für x gleich eins?
Also in einer Folge, wo Sie Nullen und Eisen haben,
die Anzahl der Fälle, wo Sie eine Eins-Folge der Länge eins haben,
wie es en halbe.
Also statistisch haben Sie an jeder zweiten Position eins stehen.
Und die Wahrscheinlichkeit für XN, dass also alles Einsen sind,
ist genau ein halb hoch en.
Das ist genau das, was wir erwarten würden.
Und hier können Sie sich auch fragen, wann haben Sie denn Erwartungswert von eins?
Also Wann tritt der auf? Und das können sie auch berechnen.
Und dann kommen sie wieder auf den Logorithmus. Das heißt,
für K gleich Tetter von Login haben sie den Erwartungswert eins.
Das heißt, wenn sie tausend Zahlen haben,
dann können sie eine Einzellänge roundabout der Länge zehn erwarten.
Wenn sie eine rein zufällige Zahlenfolge haben. So, okay
, das war das. Und damit haben wir gesehen,
was wir machen müssen und können, wenn wir nicht mehr
den Worst Case analysieren wollen, sondern den Average Case.
Und da haben sie jetzt gemerkt, da müssen wir so
ein bisschen in die Stochastik rein mit den Erwartungswerten arbeiten.
Aber wir haben ganz einfache Techniken gesehen
Seinen letzten, wenn nur die Indikator-Funktion an und lösen dann
den Therm auf. Okay,
damit wären wir da durch und nächste Woche schauen wir uns
die amortisierte Analyse an und dann werden wir mit Sicherheit auch ganz schnell dahin kommen,
dass wir uns neue Algorithmen für spannende Probleme anschauen und das
war es dann erstmal für heute