3. Kapitel: Komplexität und Komplexitätsklassen Komplexität, O-Notation Relevante Eigenschaften von Algorithmen: Korrektheit, Terminierung, Komplexität Maße für Komplexität: benötigter Speicherplatz, benötigte Rechenzeit (Laufzeitkomplexität) Schwierigkeit: abhängig von Rechner, Programmiersprache R. Der 1 Algorithmen und Datenstrukturen (Magister) Möglichkeit 1: Definition eines idealisierten Modellrechners => RAM (random access machine) • Befehlssatz ähnlich Assembler (Laden, Speichern, arithmetische Verknüpfung von Registerinhalten, Sprünge), • unendliche Menge von Speicherzellen, die natürliche oder reelle Zahlen speichern, Speicherplatz => Zahl der benötigten RAM-Zellen Laufzeit => Zahl der ausgeführten RAM-Befehle Möglichkeit 2: Genaue Ermittlung bestimmter die Laufzeit charakterisierender Parameter (Beispiel: Sortieren -> Anzahl der Vergleichsoperationen) R. Der 2 Algorithmen und Datenstrukturen (Magister) Hier: keine Formulierung der Alg. als RAM-Programme, Abschätzung der Laufzeit mit Schwerpunkt Wachstum der Laufzeit in Abhängigkeit von Eingabegröße Komplexität abhängig von Eingabegröße. Einheitskostenmaß: nur Anzahl der Daten berücksichtigt (etwa Anzahl zu sortierender Zahlen) log. Kostenmaß: auch Größe der Daten relevant (etwa Länge von Zahlen im Binärcode) worst case, average case, best case Analysen, amortisierte Kosten In der Regel genügt die Angabe der Größenordnung der Komplexität, wobei es auf konstante Faktoren nicht ankommt. R. Der 3 Algorithmen und Datenstrukturen (Magister) Beispiel: Maximum Subarray Problem gegeben: Folge X von ganzen Zahlen der Länge n gesucht: maximale Summe der Elemente einer zusammenhängenden Teilfolge Naiver Algorithmus: int o,u; double summe, maxtsumme = 0; for (u = 0; u < N; u++) for (o = u; o < N; o++) { /* bestimme Summe der Elemente in Teilfolge X[u .. o] */ summe = 0; for (i = u; i <= o; i++) summe + = X[i]; maxtsumme = max(summe, maxtsumme); } R. Der 4 Algorithmen und Datenstrukturen (Magister) Berechnung der Zahl der Schritte (Zuweisungen) Der Schleifenkörper der innersten for-Schleife for (i = u; i <= o; i++) wird o - u + 1 mal durchlaufen und dabei jeweils die Aktion (Addition) ausgeführt. Für den nächstinneren Schleifenkörper gilt for (o = u; o < N; o++) {jeweils o - u + 1 Aktionen} also 1 + 2 + 3 + ... + N-u Aktionen. In der Summe sind das (Gaussche Formel) (N-u)(N-u+1)/2 Aktionen. Die äußere Schleife enspricht dann der Aufsummation aller dieser Beiträge über u von u=0 bis u=N-1. Insgesamt ist damit die Gesamtzahl der Aktionen 1 3 1 2 1 N N N 6 2 3 Beispiel: N=32: R. Der 5984 Additionen 5 Algorithmen und Datenstrukturen (Magister) O-Notation: Seien f,g: N -> R+ Funktionen. Wir definieren: O(f) = {g | $ c > 0, n0 > 0 : g(n) <= c f(n) " n >= n0} In Worten: Die Funktion g ist von der Ordnung f, wenn für alle n> n0 eine positive Konstante c existiert, so dass g(n) <= c f(n) gilt, d.h. dass die Funktion g durch die Funktion cf majorisiert wird. Die Funktionen f und g seien beide nicht negativ. Beispiel: 3n4 + 5n3 + 7 log n O(n4), denn 3n4 + 5n3 + 7 log n < 3n4 + 5n4 + 7n4 = 15 n4 für n >= 1. Wähle also c = 15, n0 = 1. In O(n4) steht n4 für die Funktion, die n auf n4 abbildet. Häufig schreibt man auch h = O(n4) statt h O(n4) O macht Abschätzung nach oben, nach unten: W W(f) = {g | $ c > 0 , n0 > 0 : g(n) >= cf(n) " n>= n0 } R. Der 6 Algorithmen und Datenstrukturen (Magister) Alternativdefinition Ottmann/Widmayer: W(f) = {g | $ c > 0 : $ unendlich viele n: g(n)>= cf(n)} Beispiel: f(n) = 1 falls n gerade, n2 sonst. Originaldefinition liefert f = W(1), Alternativdefinition f = W(n2). Abschätzung von oben und unten (exakte Schranke) Q(f) = O(f) W(f) g aus Q(f) bedeutet also: die Funktion g verläuft ab einem Anfangswert n0 im Bereich [c1f,c2f] für geeignete Konstanten c1 , c2 . R. Der 7 Algorithmen und Datenstrukturen (Magister) Leistungsverhalten bei kleiner Eingabegröße Asymptotische Komplexität gilt vor allem für große n bei kleineren Problemen haben konstante Parameter wesentlichen Einfluß Verfahren mit besserer ( asympt. ) Komplexität kann schlechter abschneiden als Verfahren mit schlechter Komplexität T(n) Bereiche von n mit günstiger Zeitkomplexität 186182 log2 n n > 2048 1000 n 1024 <= n <= 2048 100 n log 2 n 59 <= n <= 1024 10 n2 10 <= n <= 58 n3 n = 10 2n 2 <= n <= 9 R. Der 8 Algorithmen und Datenstrukturen (Magister) Berechnung der (worst- case- ) Zeitkomplexität Elementare Operationen (Zuweisung, Ein-/ Ausgabe) : O ( l ) Summenregel: T1 ( n ) und T2 ( n ) seien die Laufzeiten zweier Programmfragmente P1 und P2 ; es gelte: T1 ( n ) O (f ( n ) ) und T2 ( n ) O ( g ( n ) ). Für die Hintereinanderausführung von P1 und P2 ist dann T(n) = T1 ( n ) + T2 ( n ) O ( max ( f ( n ), g ( n ) ) ) Produktregel: z. B. für geschachtelte Schleifenausführung von P1 und P2 T(n) = T1 ( n ) * T2 ( n ) O ( f ( n ) * g ( n ) ) R. Der 9 Algorithmen und Datenstrukturen (Magister) Programmfragmente: Fallunterscheidung: Kosten der Bedingungsanweisung ( O ( l ) ) + Kosten der längsten Alternative Schleife: Produkt aus Anzahl der Schleifendurchläufe mit Kosten der teuersten Schleifenausführung Rekursive Prozeduraufrufe: Produkt aus Anzahl der rekursiven Aufrufe mit Kosten der teuersten Prozedurausführung R. Der 10 Algorithmen und Datenstrukturen (Magister) Zeitkomplexitätsklassen Drei zentrale Zeitkomplexitätsklassen werden unterschieden: Algorithmus A heißt: linear-zeitbeschränkt fA O ( n ) polynomial-zeitbeschränkt $ k N, so daß fA O ( n k ) . $ k N , so daß exponentiell-zeitbeschränkt fA O ( kn ). R. Der 11 Algorithmen und Datenstrukturen (Magister) Komplexitätsklassen P und NP P: Die Menge aller Sprachen (Probleme), die ein deterministischer Automat in Polynomialzeit (O(P(n)) akzeptiert (löst). NP: Die Menge aller Sprachen (Probleme), die ein nichtdeterministischer Automat in Polynomialzeit akzeptiert (löst). (Beispiel SAT) R. Der 12 Algorithmen und Datenstrukturen (Magister) Definition: Nichtdeterminismus Algorithmus A heißt nichtdeterministisch, wenn A das Sprachelement OR (in beliebiger Anzahl) enthält: OR (Anw1, Anw2) bedeutet, daß entweder die Anweisung Anw1 oder die Anweisung Anw2 ausgeführt wird. Die Auswahl zwischen den beiden Anweisungen ist willkürlich. R. Der 13 Algorithmen und Datenstrukturen (Magister) P und NP als Wortproblem Es sei A ein Algorithmus und die Eingabe von A ein Element (Wort) aus * für ein Alphabet . Für jedes Eingabewort w * sei s(w) = Anzahl der Schritte bis zur Terminierung sA(n) = maximale Schrittzahl, wobei sA: 0 -> 0 mit sA(n) = max {s(w)| mit w * , |w| =n} R. Der 14 Algorithmen und Datenstrukturen (Magister) Definition: deterministischer und nichtdeterministischer Algorithmus Ein deterministischer Algorithmus akzeptiert eine Sprache L in der Zeit O(f(n)), wenn der A. für jedes beliebige Wort w innerhalb der Zeitschranke f(|w|) entscheidet, ob w L gilt oder nicht. Ein nichtdeterministischer Algorithmus akzeptiert eine Sprache L in der Zeit O(f(n)), wenn er für jedes Wort der Sprache L, das die Länge n besitzt, in O(f(n)) Schritten feststellt, dass das Wort zu der Sprache gehört. CL heisst charakteristische Funktion von L * , wenn TRUE falls w L CL (w) = FALSE falls w L R. Der 15 Algorithmen und Datenstrukturen (Magister) Definition: Eine Menge, Sprache oder ein Problem L heißt polynomialzeitbeschränkt, wenn die charakteristische Funktion CL polynomial-zeitberechenbar ist. Definition: P = { L * : L polynomial-zeitbeschränkt } heißt die Klasse der pzb-Sprachen. NP = { L * : L nichtdeterministisch polynomial-zeitbeschränkt } heißt die Klasse der npzb- Sprachen. P = { f: * * und f polynomial-zeitberechenbar } heißt die Klasse der pzb-Funktionen R. Der 16 Algorithmen und Datenstrukturen (Magister) NP = { f: * * und f nichtdeterministisch polynomial-zeitberechenbar } heißt die Klasse der npzb-Funktionen. Definitionen: Seien L, L‘ * a) L‘ heißt polynomial reduzierbar auf L dund wenn es existiert eine pzb-Funktion f: * * mit: " w * w L‘ f ( w ) L b) L heißt NP-schwierig dund wenn für jedes L‘ NP gilt: L‘ ist polynomial reduzierbar auf L. c) L heißt NP-vollständig dund wenn L NP und L ist NP-schwierig. R. Der 17 Algorithmen und Datenstrukturen (Magister) Lösungsstrategien/Arten von Algorithmen Kleine n: Beschränkte Eingabegrößen Teile-und-Herrsche: Aufteilung eines Problems in Teilprobleme (die rekursiv gelöst werden können) Probabilistische A.: Optimierung der durchschnittlichen Kosten durch Annahmen über statistische Eigenschaften der Eingabe-größen (z.B. Randomisierung, Wahrscheinlichkeitshäufung) Approximierung: Errechnung einer hinreichend guten Lösung in einem beschränkten Suchraum (z.B. durch Heuristiken) Greedy Algorithms: Errechnung lokaler Optima Dynamische Programmierung: Aufteilung eines Problems in Teilprobleme und Wiederverwendung von Lösungen für Teilprobleme R. Der 18 Algorithmen und Datenstrukturen (Magister) Divide and Conquer Methode Allgemein: Divide and Conquer- Verfahren zur Lösung eines Problems der Größe n 1. Divide: Falls n > 1 teile Problem in annähernd gleich große Teilprobleme, sonst löse Problem direkt. 2. Conquer: Löse (rekursiv) Teilprobleme. 3. Merge: Kombiniere Teillösungen zu Gesamtlösung. R. Der 19 Algorithmen und Datenstrukturen (Magister) Anwendung auf Maximum Subarray Problem: Beobachtung: wenn man Folge in 2 Teile A und B teilt, so ist die gesuchte Teilfolge entweder in A, oder in B, oder in beiden. Im letzten Fall sind die Randelemente in der gesuchten Teilfolge, und diese besteht aus 2 maximalen Teilstücken, die beim jeweiligen Rand beginnen (rechtes Randmaximum von A + linkes Randmaximum von B) . Die Randmaxima von X[l], ..., X[r] kann man in linearer Zeit berechnen: lmax := 0; summe := 0; for i := l to r do begin summe := summe + X[i]; lmax := max(lmax, summe) end rmax analog. R. Der 20 Algorithmen und Datenstrukturen (Magister) Damit erhält man folgenden D&C-Algorithmus: Algorithmus maxtsum(X); {liefert maximale Teilsumme der Folge X ganzer Zahlen} begin if X enthält nur ein Element a then (if a > 0 then maxtsum := a else maxtsum := 0) else begin teile X in linke und rechte Teilfolgen A und B annähernd gleicher Größe; maxtinA := maxtsum(A); maxtinB := maxtsum(B); bestimme rechtes Randmaximum von A, rmax(A); bestimme linkes Randmaximum von B, lmax(B); maxtsum := max(maxtinA, maxtinB, rmax(A) + lmax(B)) end end R. Der 21 Algorithmen und Datenstrukturen (Magister) Sei T(n) Anzahl der Schritte des Algorithmus bei Eingabe einer Folge der Länge n. Es gilt: T(n) = 2 T(n/2) + C . n Da T(1) konstant (T(1) = C1) erhält man T(n) = Q(n log n). Beispiele: T(1) T(2) T(4) T(8) T(16) T(32) = C1 = 2C1+ 2C = 4C1 + 8C = 8C1 + 24 C = 16C1 + 64 C = 32C1 + 160 C Gleichungen wie die obige nennt man Rekursionsgleichungen. (Sie treten bei Komplexitätsanalysen oft auf.) R. Der 22 Algorithmen und Datenstrukturen (Magister) Noch besseres Verfahren: Scan-Line-Prinzip. wir durchlaufen Positionen 1,...,n, merken uns jeweils die maximale Summe bismax im bisher inspizierten Anfangsstück sowie rechtes Randmaximum scanmax. Bei Vorrücken um 1 Position ist neue maximale Teilfolge entweder gleich der alten, oder sie enthält neues Randelement und ist dann das neue rechte Randmaximum. Neues rechtes Randmaximum ist scanmax + a, a Wert der nächsten Position, falls diese Summe positiv, sonst 0. scanmax := 0; bismax := 0; for i := 1 to n do begin if scanmax + X[i] > 0 then scanmax := scanmax + X[i] else scanmax := 0; bismax := max(scanmax, bismax) end R. Der 23 Algorithmen und Datenstrukturen (Magister)