cards-deck: 100-199_university::111-120_theoretic_cs::111_algorithms_datastructures

Master Theorem | solving simple recurrence relations:

anchored to [[111.00_anchor]]


Overview:

Das Master-Theorem kann angewandt werden um die Einordnung einer Laufzeitklasse bei einer rekursiv definierten Funktion bestimmen zu können.

[!Warning] Nicht jede rekursive Funktion kann mit diesem bestimmt werden.

In unserem Kontext haben wir etwa bei der Anwendung von Divide-And-Conquer-Algorithmen oft eine solche Struktur, die Probleme nach und nach in kleinere aufteilt und dabei rekursiv agiert.


Definition:

Die allgemeine Form des Master-Theorem wird folgend beschrieben: wie wir sie angewandt, was bedeuten ihre Parameter? #card wobei folgend:

  • die Laufzeitfunktion
  • Konstanten mit
    • beschreibt die Anzahl an Unterproblemen in der Rekursion
    • stellt einen Teil des Originalproblemes dar, wobei es durch all seine Unterprobleme repräsentiert wird
  • die Funktion darstellt und beschreibt, welchen Aufwand, oder welche Nebenkosten durch das Teilen des Problems, und dem Kombinieren der Teillösungen aufkommen. ^1704708610210

[!Important] Betrachtung zu was müssen wir bei diesen Parametern beachten? #card dürfen nicht von ( also der Größe des Problemes) abhängen! ^1704708610218

Um diese Faktoren entsprechend bestimmen zu können, wäre es wohl sinnvoll Divide-and-Conquer zu betrachten:

Divide and Conquer:

Angenommen wir haben ein Problem der Größe . Normalerweise kann es jetzt sein, dass gestellte Problem mit Berechnungen oder ähnlichem gelöst werden kann, aber vielleicht sehr langsam ist bzw schlecht mit hohen skaliert. Wir wollen also folgend das Groß Problem in kleinere Probleme aufteilen.

Bei Divide and Conquer folgen wir immer dem gleichen Prinzip zur Analyse der Laufzeit:

  1. beschreibt die gesamte Laufzeit in Abhängigkeit von .
  2. Wir haben jetzt Subprobleme, die wir aus dem großen Problem erzeugen.
  3. beschreibt den Faktor, mit welchem die Subprobleme aufgebaut werden. Daraus können wir etwa die Größe eines Subproblemes bestimmen:
  4. Wir gehen davon aus, dass die Kombination der Teillösungen Zeit benötigt.

Aus dieser Betrachtung können wir jetzt die obige Formel konstruieren:

Master-Theorem | Folgerung:

Wir können aus dieser Betrachtung jetzt 3 Fälle erzeugen: Betrachte hierfür nochmals das Theorem: Dafür gelte, dass , dann folgt: welche und was sagen sie uns? #card Fall 1: oder auch folgt: –> das kommt daher, dass der log aus größer ist, als der Exponent der Funktion wodurch wir dann wissen, dass die Laufzeit nicht von der Funktion bedingt wird! Fall 2: und es folgt : –> das kommt daher, dass hier die Funktion genauso schnell schnell wächst, wie der Rest, wodurch wir die Laufzeit bestimmen können. Es gibt hier auch noch einen Spezialfall, der manchmal angewandt werden kann! Fall 3: wobei wir hier aufteilen müssen:

  • –> um die erste Aussage zu zeigen
  • oder einfach Folgt jetzt: bzw. auch einfach beschrieben als , weil ja den Exponent der Funktion angibt! ^1704708610222

[!Important] Spezialfall für Fall 2: Wenn wir etwa einen logarithmus in der Funktion haben, können wir manchmal das Master-Theorem trotzdem anwenden!

Dafür muss folgendes gelten: oder anders formuliert: Können wir also unsere Funktion mit der obigen Schreibweise darstellen bzw. stimmt sie überein, können wir das Master-Theorem anwenden!

Es folgt hier jetzt Wichtig ist hier, dass der ln in seiner Potenz um eins erhöht wird!

Trick | Logarithm conversion:

Bedenke, dass wir den Logarithmus entsprechend konvertieren können: und weiter auch:

Beweis des master theorem:

Um das Master-Theorem zu beweisen, kann man das Problem in Form eines Baumes betrachten und daraus das Prinzip Stufe für Stufe betrachten.

Wir wollen dafür ein Problem der Größe betrachten und es via Divide-and-Conquer in Probleme aufteilen. ![[Pasted image 20221024142928.png]] Was wir hier sehen können:

  • Ein großes Problem wird in -viele kleinere Probleme aufgeteilt.
  • mit wird angegeben, wie viele Brnaches wir pro Stufe erzeugen werden.
  • jedes der Probleme wird anschließend wieder in teile aufgeteilt.
    • Dadurch haben wir ab der zweiten Stufe bereits Probleme
  • Dieser Prozess teilt sich weiter und weiter in kleinere Probleme auf
  • bis wir Probleme der Größe erhalten

Wenn wir jetzt die Probleme auf unterster Ebene gelöst haben, müssen sie wieder zusammengefasst werden: Die Kosten für jede Berechnung aus dem unterem zum oberen Level ( also das Kombinieren der Lösungen) brauch .

Tiefe des Baumes:

Wir möchten jetzt betrachten, wie viele Ebenen wir brauchen, um das Ende des Baumes zu erreichen. Wir wissen, dass das Problem mit jeder Stufe kleiner wird. wie lang benötigen wir jetzt, um bis zum Grund des Baumes zu kommen? #card Wir wollen folgend lösen, ab wann gilt“ , und müssen also height bestimmen = –> die Menge an Ebenen, ist also abhängig von ! ^1704708610226

Stufe in Ebene:

Auf jeder Stufe des Baumes müssen wir bestimmte Dinge beachten:

  1. Auf Ebene haben wir insgesamt subprobleme ( also die Breite des Baumes wird damit beschrieben.)
  2. Jedes dieser Subprobleme hat hierbei eine Größe von
  3. Grundsätzlich wird auf der Ebene keine extra Arbeit verursacht! Sie entsteht nur durch das Kombinieren der Lösungen darunter.
    1. Es werden jetzt weitere Subprobleme aufgerufen und diese wiederholen den Prozess.

[!Important] Recombination pro Stufe kostet! Jede Stufe hat weitere Probleme unter sich, wobei ihre Lösungen wieder kombiniert werden müssen. Dieser Prozess kostet Zeit, die wir folgend beschreiben können: wie? #card Dieser Vorgang wird für jedes Probleme durchgeführt, also haben wir am Ende eine erweiterte Laufzeit: ^1704708610230

Boden des Baumes:

Wir können die Menge von Problemen am Boden des Baumes (also der untersten Ebene unserer Problem-Aufteilung) folgend bestimmen: #card Wir wissen, dass jedes dieser Probleme in der Komplexität entspricht. brauchen wir jetzt Zeit für die unterste Stufe! ^1704708610234

Gesammelte Zeit für den Divide-And-Conquer-Baum:

Wir haben jetzt alle Ebenen und Schritte zur Bildung der Lösung betrachtet. Aus den einzelnen Ergebnissen können wir jetzt aufbauen, wie die gesamte Laufzeit aussehen muss: #card

[!Info] Aufbau der Gesamtzeit: Wir können sie aber besser konstruieren bzw. umstruktieren: die Summe entspricht hierbei der [[math1_Folgen#Beispiel ==Geometrische Folge==|geometrischer Folge]] bzw Reihe und wird demnach folgende Zustände haben: , wenn . , wenn , wenn Da wir bei uns folgenden Zustand haben, können wir die 3 Fälle aus der Definition resultieren! , sowie ^1704708610239

Beispiel:

Betrachten wir die naive Implementation der Integer-Multiplikation nochmal [[111.04_laufzeitanalyse_onotation#Beispiele zur Bestimmung der Laufzeit]]. Wir resultieren hier mit Hier haben wir jetzt folgende Attribute: , Wenn wir jetzt die 3 Fälle betrachten: und somit ist also haben wir den dritten Fall erreicht. Daraus folgt jetzt die Laufzeit: