Universitat Konstanz Skript zu Informatik II im Sommersemester 1999 Karsten Weihe Konstanzer Schriften in Mathematik und Informatik Nr. 94, Juli 1999 ISSN 1430{3558 c Fakultat fur Mathematik und Informatik Universitat Konstanz Fach D 188, 78457 Konstanz, Germany Email: [email protected]{konstanz.de WWW: http://www.informatik.uni{konstanz.de/Schriften Informatik II Generalthema: Algorithmen und Datenstrukturen Eine beispielorientierte Einfuhrung in Algorithmen und Datenstrukturen (mit Java) Algorithmus: Vorgehensweise zur Erzielung eines Ergebnisses, ohne dabei nachdenken zu mussen ("Kochrezept\). ;! Auch durch Computer ausfuhrbar. Datenstruktur: Speicher fur die von Algorithmen zu bearbeitenden bzw. fur zusatzlich dafur verwendete Daten. Wichtigste zu betrachtende Aspekte: Sommersemester 1999 Universitat Konstanz Karsten Weihe Informatik II { Sommersemester 1999 1 Modellbildung, Korrektheit der Losungen, Ezienz (Laufzeit), Speicherplatzverbrauch. Informatik II { Sommersemester 1999 2 Thema 1: Algorithmische Problemstellung Fallbeispiel: "passendste\ interpolierende nichtverti- Oene Frage: Was heit eigentlich "passendst\? Eingabe: n Mepunkte (x1; y1); : : : ; (xn; yn). Ausgabe: Steigung der Geraden und ihr Schnittpunkt mit der y-Achse. Problem: Bei steilem Anstieg ware eher die horizontale Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 kale Gerade fur Mewerte 3 1. Ansatz fur "passendst\: Summe der vertikalen Abstande minimal. Abweichung signikant. ;! Keine gute Modellbildung. 4 2. Ansatz fur "passendst\: Summe der lotrechten Abstande minimal Wichtigster Ansatz in der Praxis: Methode der kleinsten Quadrate. Auch Regressionsanalyse genannt (;! Statistik). Summe der Quadrate der vertikalen Abstande soll minimiert werden. ;! Schon recht genau das, was man will. Wirklich die "beste\ Denition? Gibt es uberhaupt die "beste\ Denition!? Informatik II { Sommersemester 1999 5 Problem: "Ausreier\ (d.h. ernsthafte Mefehler) haben uber- proportionalen Einu auf das Ergebnis. Falls Ausreier durch einseitigen Mefehler erzeugt werden: ;! Systematische Verfalschung des Ergebnisses wird noch verstarkt! Informatik II { Sommersemester 1999 6 Frage: Warum wird dennoch ausgerechnet diese Denition gewahlt? Pragmatische Antwort: Diese Denition ist mathematisch (und somit algorithmisch) vergleichsweise einfach handhabbar! Moglicher Ausweg: "Ausreier\ aus der Betrachtung herausnehmen. Beispiel fur eine exakte Denition des Auswegs: Finde die Gerade, die "am passendsten\ ist, wenn nur die 90% Mepunkte, die am nachsten an dieser Gerade liegen, in die Summe der quadrierten Abstande eingehen. Informatik II { Sommersemester 1999 7 Informatik II { Sommersemester 1999 8 U ber-/Unterspezikation Merke: Uberspezikation: Exakte Problemdenition ist ein- Zur automatisierten Bearbeitung eines algorith- schrankender formuliert als eigentlich beabsichtigt. Unterspezikation: Exakte Problemdenition enthalt nicht alle eigentlich beabsichtigten Einschrankungen. mischen Problems braucht man eine exakte Problemdenition. Zu spezizieren sind die zulassigen Eingaben und das gewunschte Ergebnis, das fur eine zulassige Eingabe berechnet werden soll. Alltagsformulierungen\ sind typischerweise "nicht exakt genug. Die exakte Denition zu einer Alltagsformulierung gibt es nicht unbedingt. ;! Freiheitsgrade bei der Umsetzung. Diese Freiheit kann man nutzen, um zu einer moglichst gut algorithmisch handhabbaren Problemdenition zu kommen. Informatik II { Sommersemester 1999 Achtung: U berspezikation kann leicht durch Verwirrung von algorithmischer Problemstellung und algorithmischer Vorgehensweise passieren! Beispiel: Ausreier bei der Bestimmung der "passendsten\ Megerade eliminieren. Falle: Die 90% "am besten passenden\ Mepunkte werden schon in der Problemstellung speziziert. 9 Konkretes Beispiel: Die 10% Mepunkte mit den Winkeln vom Nullpunkt aus gesehen "exzentrischsten\ sollen aus der Berechnung der Summe der Abstandsquadrate herausfallen. Informatik II { Sommersemester 1999 10 Merke: U berspezikationen passieren leicht dadurch, da man dem Algorithmus unbeabsichtigt "Arbeit abnimmt\. Dadurch ist der Algorithmus in seinen Moglichkeiten unnotig (und vielleicht entscheidend!) eingeschrankt. Also: Algorithmische Problemstellung und algorithmische Vorgehensweise beim Nachdenken konsequent auseinanderhalten. Logische Inkorrektheit: Die 10% Mepunkte sollten nicht a priori gegeben sein, sondern sich eigentlich erst aus dem Ergebnis des Algorithmus ergeben. Informatik II { Sommersemester 1999 11 Informatik II { Sommersemester 1999 12 Noch einmal zuruck zum Thema algorithmisch gut handhabbare Problemstellungen\ " Extremfall: algorithmenorientierte statt problemorien- tierte Spezikation der algorithmischen Problemstellung. Newton{Verfahren: xn+1 := xn ; ff0((xxn)) (n 0) n Beispiel: Eingabe: Funktion f : R ;! R , Ableitungsfunktion f 0 sowie ein x0 2 R . Ausgabe: Nullstelle von f . Zulassige Eingaben: f konvex und streng monoton zwischen x0 und Nullstelle. ;! Newton{Verfahren zur Nullstellenberechnung liefert beweisbar eine korrekte Losung. x3 x 2 x1 x0 Frage: Wozu sind solche algorithmen- statt problemorientierte Spezikationen gut? Informatik II { Sommersemester 1999 13 Wozu algorithmenorientierte Spezikationen? Informatik II { Sommersemester 1999 14 Veranschaulichung Quadratwurzelberechnung Antwort: Als "gemeinsamer Nenner\ fur diverse Spe- per Newton{Verfahren: zialfalle, die durch denselben schnellen, aber nicht allgemein anwendbaren Algorithmus gelost werden konnen. Beispiel fur solche Spezialfalle: Quadratwurzelberechnung. Zulassige Eingabe: y 2 R , y 0. Gewunschte Ausgabe: py. Losungsidee: Finde nichtnegative Nullstelle der Funktion f : R ;! R mit f (x) = x2 ; y. Startlosung: x0 := maxf1; yg. ;! x0 py garantiert. Informatik II { Sommersemester 1999 - y 15 Informatik II { Sommersemester 1999 -y y max{1,y } 16 Variationen vs. Spezialfalle von algorithmischen Problemstellungen Zuruck zum Thema Megerade ... Beispiele fur Variationen: Die Gerade soll nicht durch Steigung und Schnitt Beispiele fur Spezialfalle: Alle Mepunkte haben ganzzahlige Werte. Es gibt niemals mehr als 100 Mepunkte. Keine zwei Mepunkte haben dieselbe x{Koordinate. Informatik II { Sommersemester 1999 17 Beliebter Denkfehler: Manche Variation sieht wie Spezialfall aus ;! scheint einfacher (ezienter) losbar zu sein. Beispiel: Gerade soll ganzzahlige Steigung haben. Kein Spezialfall, sondern nur\ eine Variation (und tatsachlich auch wesentlich"aufwendiger zu losen!). Informatik II { Sommersemester 1999 19 punkt mit der y-Achse, sondern durch zwei Punkte auf der Geraden ausgegeben werden. Die Gerade mu durch den Nullpunkt gehen. Die Steigung soll ganzzahlig sein. Vertikale Geraden sind zugelassen. Allgemeinere Kurven anstelle von Geraden. Dreidimensionale Variante des Problems. Informatik II { Sommersemester 1999 18 Merke: Ein Spezialfall liegt vor, wenn die zulassigen Eingaben fur den Algorithmus eingeschrankt werden. Alles andere sind Variationen. Insbesondere: Einschrankungen bei der Ausgabe konstituieren keinen Spezialfall, sondern eine Variation! Nur wenn A ein wirklicher Spezialfall von B ist, kann man logisch folgern, da A mindestens genauso ezient losbar ist wie B . Ist A nur eine Variation von B , lat sich ohne weiteres Wissen uber A und B gar nichts folgern. Informatik II { Sommersemester 1999 20 Fallbeispiel aus der Praxis: Vereinfachtes Beispiel fur Ablaufplane: Auftragsplanung im Stahlwerk (stark vereinfacht!) Jeder Kundenauftrag speziziert Metallschmelze { spatesten Liefertermin, { Art des Produkts Warmwalzen Abkühlen (z.B. Draht, Blech, Trager...), { Abmessungen (z.B. Drahtdurchmesser/-lange, Blechstarke/-breite/-lange), { Material und Legierung, { Sonderbehandlungen (z.B. Farbung, Beizung...). Kundenauftrag wird in Ablaufplan umgesetzt. Ablaufplan: Folge von Operationen auf verschiedenen Maschinen, um das Endprodukt aus einer Schmelze herzustellen. Informatik II { Sommersemester 1999 Transport zum Kaltwalzwerk Kaltwalzen Transport Drahtziehen Transport Färben Lagerung zum Trocknen Transport ins Endlager Endprodukt 21 Algorithmisches Ziel: Zeitliche Einplanung 22 Was soll passieren, wenn der Algorithmus keine aller Operationen, so da alle Nebenbedingungen erfullt sind: Losung ndet? Jede Operation hat ihre spezische Bearbeitungs- zeit. Jede Maschine bearbeitet zu jedem Zeitpunkt maximal eine Operation. Minimale und maximale Ubergangszeiten zwischen zwei aufeinanderfolgenden Operationen eines Auftragsplans mussen eingehalten werden. Beobachtungen: Die Nebenbedingungen konnen das Problem unlosbar machen. Falls uberhaupt losbar, kann es mehrere Losungen geben. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 23 Mogliche, sinnvolle Antworten: Er soll eine "moglichst wenig inkorrekte\ Losung liefern. ;! Einige der "harten\ Nebenbedingungen mussen zu "weichen\ Zielsetzungen werden (z.B. Einhaltung aller Liefertermine). Er soll eine Diagnostik liefern, z.B. { welche Maschinen wann jeweils der "Flaschenhals\ sind, { welche Liefertermine unmoglich einzuhalten sind. ;! Hilfreiche Information, damit Druck durch geeignete betriebliche Manahmen abgefangen werden kann (z.B. zusatzliche Arbeitsschichten). Zur Diagnostik konnen auch konkrete Vorschlage fur solche betrieblichen Manahmen gehoren. Informatik II { Sommersemester 1999 24 Allgemein beliebte Falle: Vergessen von Merke: "simplen\ Randfallen Beispiel: Maschine im Stahlwerk kann uber den gesamten betrachteten Zeitraum hinweg auer Betrieb sein. Ein algorithmisches Problem kann mehrere Losungen haben. Oder auch gar keine. Exakte Denition der algorithmischen Problemstellung mu ggf. auch das Ergebnis "keine Losung\ zulassen. Insbesondere bedeutet Ergebnis "keine Losung\ nicht unbedingt Fehlverhalten des Algorithmus. Typische Variationen zur Behandlung dieser Aspekte sind: { Forderung nach mehreren alternativen Losungen zum Auswahlen, { diagnostische Zusatzausgaben, { Eingrenzung der Losungsmenge anstelle von konkreten Losungen. Informatik II { Sommersemester 1999 Beispiel fur Konsequenzen: Algorithmus darf nir- gendwo einfach durch die Gesamtbetriebszeit einer Maschine dividieren! Problem konnte im Prinzip dadurch gelost werden, da eine solche Maschine aus der Betrachtung genommen wird. Aber: Konnte potentiell zu umstandlich sein. Also: Damit keine Zweifel aufkommen, sollte die Spezikation der algorithmischen Problemstellung ausdrucklich den Fall Gesamtbetriebszeit 0 einschlieen. 25 26 Thema 2: Generische Problemstellungen Merke: Wieder zuruck zum Beispiel \`interpolierende Megerade\... Bei der genauen Spezikation einer algorith- mischen Problemstellung mu immer besonderes Augenmerk auf die "Randfalle\ gelegt werden. Da ein Randfall "prinzipiell vermeidbar\ ware, bedeutet nicht unbedingt, da er in der Praxis auch wirklich unter allen Umstanden vermieden wird. Oft ist es namlich einfach zu umstandlich, den Randfall vorab abzufangen. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 Beobachtung: Der genaue Zahlentyp spielt fur die algorithmische Problemstellung keine Rolle. Allgemein: Jeder Zahlentyp, auf dem der Abstand zwischen Punkten (x1; y1) und (x2; y2) deniert ist, kann in die Problemstellung eingesetzt werden. 27 Naturliche Zahlen Ganze Zahlen Rationale Zahlen Reelle Zahlen ... Informatik II { Sommersemester 1999 28 Fortsetzung Generizitat Intuition hinter "Manhattan{Distanz\: Weitere Beobachtung: Verschiedene Abstandsde- nitionen (Metriken) konnen auf demselben Zahlentyp deniert sein. Beispiele: Normaler (Euklidischer) Abstand: Lange der Verbindungsstrecke p (x1 ; x2)2 + (y1 ; y2)2 (Mathematischer Begri: 2{Metrik) Manhattan-Distanz: jx1 ; x2j + jy1 ; y2j (Fahrdistanz in Manhattan{artig angelegten Stadten; mathematisch: 1{Metrik) Informatik II { Sommersemester 1999 29 "Esoterische\ Beobachtung: Informatik II { Sommersemester 1999 30 Standardbeispiel fur Generizitat: Sortieren Man braucht sich eigentlich gar nicht auf Zahlentypen zu beschranken. Jede Menge mit einem Abstandsbegri ist moglich. Beispiel: Strings der Lange m mit Hamming-Abstand Gegeben: Sequenz (a1; : : : ; an) von zu sortierenden Werten. Gesucht: Permutation der Sequenz, so da gilt: (a1) (a2) (an) Einfaches Zahlenbeispiel: Abstand zweier Strings = 17 21 41 67 12 41 15 23 88 9 Anzahl der ungleichen Zeichen 9 12 15 17 21 23 41 41 67 88 Informatik II { Sommersemester 1999 31 Informatik II { Sommersemester 1999 32 Generische Freiheitsgrade: Datentyp fur die Werte a1; : : : ; an, Konkretes Beispiel: Datensatze fur immatrikulierte Denition von "\, Datentyp fur die Sequenz (z.B. Array). Vorgri: Fur die meisten in dieser Vorlesung behan- delten Sortieralgorithmen ist die Festlegung dieser drei Freiheitsgrade unerheblich! Studierende. Enthalten als Daten z.B. Vorname, Nachname, Fachrichtung, Matrikelnummer. Sinnvolle Denitionen von "\: { "Telefonbuchordnung\ auf den Namen (Fachbegri: lexikographisch) ;! Reihenfolge nicht eindeutig. { Nach Matrikelnummern ;! Reihenfolge eindeutig. { Nach Geburtsdaten ;! Reihenfolge wieder nicht eindeutig. ;! Spater mehr zum Thema Sortieren. Informatik II { Sommersemester 1999 33 Mathematische Exkursion: abstrakte Informatik II { Sommersemester 1999 34 Technische Exkursion: potentielles Zusammenfallen Datentypen von Ein- und Ausgabe Beispiel: wieder Immatrikulationsdaten Datentyp = Menge von moglichen Werten + Operationen + axiomatische Regeln fur die Operationen StudentIn[] sort (StudentIn[] A) Erlauterung: Beispiel: Mathematische Gruppe. Eingabe: Parameter A. Ausgabe: Ruckgabewert von sort. tion. Rationale und reelle Zahlen (ohne 0) jeweils mit Multiplikation. Alternative: Generischer Algorithmus Algorithmus auf abstrakten Datentypen. A Ganze, rationale und reelle Zahlen jeweils mit Addi- Informatik II { Sommersemester 1999 { ... } void sort (StudentIn[] A) { ... } ist nun Ein- und Ausgabe ;! eine Kopieraktion eingespart. 35 Informatik II { Sommersemester 1999 36 Weiteres Beispiel fur generische algorithmische Pro- Schnellste Fahrverbindung mit dem Zug: blemstellungen: Optimale Verbindungen in Netzwerken Generische Problemstellung Kürzeste Autoverbindung Schnellste Bahnverbindung Billigste Flugverbindung Preis\ einer Verbindung von A nach B (vereinfacht): "Summe der Einzelpreise fur die elementaren Fahrten. ;! Problemstellung benotigt zwei Operationen auf dem Datentyp fur Preise: Addition und Minimumsbildung. Informatik II { Sommersemester 1999 37 Sinnvolles Beispiel fur generisches Oenhalten des Zahlentyps: "Preis\ einer elementaren Fahrverbindung: Paar (a; b) von Zahlen. Addition: (a; b) + (c; d) = (a + c; b + d). Minimum von (a; b) und (c; d): = (a; b) falls a < c, = (a; b) falls a = c und b < d, = (c; d) sonst. Sinn des Ganzen: 38 Zunachst obskur erscheinende generische Variation: Ersetze Addition durch Multiplikation und Minimum durch Maximum. DM ÖS SFr US $ ;! "Kurzeste\ Verbindung von Wahrung A nach Wahrung B mit Umtauschkurs als "Preis\ ergibt gunstigste Umtauschkette. ;! Auch dieses Problem ist im Prinzip mit demselben Algorithmus fur "kurzeste Wege\ losbar! 1. Zahl: Fahrpreis. 2. Zahl: Fahrzeit. ;! Optimaler Pfad mit diesem "Zahlentyp\ und dieser Denition von Addition und Minimumsbildung ist die schnellste Verbindung unter allen billigsten! Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 39 Informatik II { Sommersemester 1999 40 Unerwartetes Beispiel fur kurzeste Wege: Blockformatierung von Texten in Textverarbeitungssystemen Knotenpunkte: alle Silben sowie "{ Ende {\. Verbindung: Von jeder Silbe zu jeder nachfolgenden. "Preis\ einer Verbindung: der zu"Haolichkeitsgrad\ geh rigen Zeile. Formatierung Pfad von erster Silbe bis "{ Ende {\. Un er war te tes Bei spiel für kür ze ste We ge: Block for ma tierung von Tex ten in Text ver ar bei tungs sy ste men -Ende - Informatik II { Sommersemester 1999 Merke: In vielen Problemstellungen kann der zu- grundeliegende Datentyp in gewissen Grenzen oengelassen werden, und Losungsalgorithmen werden mit den sich ergebenden Variationsmoglichkeiten trotzdem fertig. Fur den Datentyp mussen nur gewisse Operationen deniert sein, die fur die Problemstellung wesentlich sind. Weiterer Freiheitsgrad: Diese Operationen konnen unterschiedlich deniert sein (auch in ungewohnlicher, unerwarteter Weise). 41 Technische Exkursion: Wie kann man die Implemen- tation eines Algorithmus in Java so generisch wie den Algorithmus selbst halten? Informatik II { Sommersemester 1999 42 Ergebnis: void sort (Object[] A, Comparator cmp) { ... Idee: Konkreten Datentyp durch den "allumfassenden\ Typ comp.lang.Object ersetzen. Operation "\ durch einen weiteren Parameter von einem neuen Typ Comparator\ reprasentieren. " // Beispielhafte Anwendung von "isLessThan": if ( cmp.isLessThan(A[i],A[j]) ) ... } "Comparator\ hat Methode boolean isLessThan (Object obj1, Object obj2) zum Vergleich zweier Werte des Datentyps. Informatik II { Sommersemester 1999 43 Informatik II { Sommersemester 1999 44 Implementation von "isLessThan\ Beispiel: fur Datentyp int und gewohnliche Ordnungsrelation auf ganzen Zahlen. Kurzer Ausblick: Java{Erweiterung GJ (Generic Java) Implementation von isLessThan: boolean isLessThan (Integer int1, Integer int2) { int i1 = int1.intValue(); int i2 = int2.intValue(); return i1 < i2; } boolean isLessThan (Object obj1, Object obj2) { Integer int1 = (Integer)obj1; Integer int2 = (Integer)obj2; int i1 = int1.intValue(); int i2 = int2.intValue(); return i1 < i2; } Nun sort selbst: <T> void sort (T[] A, Comparator<T> cmp) { ... Achtung: void sort (Object[] A, Comparator cmp) Paar (A,cmp) ist nur dann eine zulassige Eingabe, wenn alle Komponenten von A den Datentyp haben, der von cmp.isLessThan erwartet wird. Informatik II { Sommersemester 1999 45 <T> void sort (T[] A, Comparator<T> cmp) sort Bemerkung: Generische Typen und Prozeduren gibt es in verschiedenen Programmiersprachen (z.B. Ada, C++, Eiel, Haskell, ML), aber eben (noch?) nicht in Java. Informatik II { Sommersemester 1999 } Informatik II { Sommersemester 1999 46 Merke: Erlauterung: Datentyp ist jetzt explizit, aber immer noch generisch (d.h. durch einen "Platzhalter\, im Beispiel durch "T\) in der Implementation von formuliert. ;! Beim U bersetzen wird schon automatisch getestet, ob A und cmp zusammenpassen. ;! Die "Zeitbombe\ ist "entscharft\. // Beispielhafte Anwendung von "isLessThan": if ( cmp.isLessThan(A[i],A[j]) ) ... 47 Im Prinzip lassen sich generische Algorithmen in Java auch entsprechend generisch implementieren. Allerdings mu beim Programmieren "per Hand\ darauf geachtet werden, da die Datentypen der Eingabeparameter zusammenpassen. In groeren Programmen kann man leicht die U bersicht verlieren und Fehler einbauen, die dann oftmals muhselig und langwierig durch Testlaufe zuruckverfolgt werden mussen. In anderen Programmiersprachen gibt es sogenannte generische Sprachkonstrukte (auch Templates genannt), die dafur sorgen, da der Compiler jeden solchen Fehler anzeigt. Informatik II { Sommersemester 1999 48 Thema 3: Korrektheit von Algorithmen Wiederholung aus Thema 1: Spezikation einer algorithmischen Problemstellung gibt die zulassigen Eingaben an und beschreibt das gewunschte Ergebnis fur eine zulassige Eingabe in allgemeiner Form. Denition: Ein Algorithmus heit korrekt bzgl. ei- ner (exakt spezizierten!) algorithmischen Problemstellung, wenn er bei einer zulassigen Eingabe nur wohldenierte Schritte macht, terminiert (d.h. in keine Endlosschleife lauft) sowie bei Termination das laut Spezikation gewunschte Ergebnis liefert. Informatik II { Sommersemester 1999 49 Achtung: Wohldenierte Schritte... Beispiele fur nicht wohldenierte Schritte: Division durch 0, Operationen mit arithmetischem U berlauf, Zugri auf Arraykomponente auerhalb des Indexbereichs, Zugri auf nichtinitialisierte Variable. Beachte: Nicht wohldenierte Schritte fuhren zu undeniertem Verhalten des Programms im weiteren: Programmabsturz, Endlosschleife, Rechnerstillstand, Termination mit inkorrekten Ergebnissen Termination mit korrekten Ergebnissen ... Informatik II { Sommersemester 1999 50 Merke: Arithmetischer U berlauf kann manchmal uberraschend schnell passieren! Beispiel: Binomialkoezient berechnen mittels Fakultat m! = 1 2 3 (m ; 1) m. n n! k := k! (n ; k)! Korrektheit eines Algorithmus ist nicht abso- lut, sondern immer nur relativ zur zugrundeliegenden Spezikation der algorithmischen Problemstellung zu verstehen. Zur Korrektheit gehoren als Grundvoraussetzungen Wohldeniertheit und Termination. int binomcoeff (int n, int k) { return faculty(n) / (faculty(k) * faculty(n-k)); } Problem: Java{Datentyp int kann nur Zahlen bis 231 ; 1 = 2:147:483:647 darstellen. ;! Arithmetischer U berlauf schon fur n 13. Informatik II { Sommersemester 1999 51 Informatik II { Sommersemester 1999 52 Korrektheit unter numerischer Unsicherheit Beispiel: Quadratwurzelberechnung Problem: Die meisten Quadratwurzeln sind irrationale Zahlen. ;! Problem ist prinzipiell nicht exakt losbar. Wichtigste Beispiele fur Abstandsfunktionen in der Praxis: Absoluter Fehler: x x0, wenn jx ; x0j " ist. Relativer Fehler: x x0, wenn gilt: jx ; x0j " maxfx; x0g. Grundidee: Approximative Losung x fur die eigentliche Losung x0 wird als korrekt gewertet, wenn x x0. x x0 ist auf Basis einer Abstandsfunktion und eines festen Schwellwerts " > 0 deniert: x x0, Unterschied: Aussagekraft des relativen Fehlers hangt Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 wenn der Abstand zwischen x und x0 den Schwellwert " nicht uberschreitet. 53 nicht von der Groenordnung der (willkurlich gewahlten) Konstante " im Verhaltnis zu x und x0 ab. 54 Beispiel: Konkrete Idee fur Quadratwurzelberechnung mittels Newton Merke: Es gibt algorithmische Probleme, die prinzipi- ell nicht exakt losbar sind. Ursache: Diskrepanz zwischen mathematischen Zahlen mit unendlicher Genauigkeit und Maschinenzahlen mit endlicher Stellenzahl. In einem solchen Fall mu die gesuchte Losung approximiert werden. Besonders bewahrt in der Praxis: relativer Fehler als Ma fur die Gute einer approximativen Losung. Informatik II { Sommersemester 1999 - y -y y max{1,y } Sei z 2 (0; py ] beliebig ;! f 0(x) = 2x 2z = f 0(z) fur x py ;! f (x) g(x) := 2z (x ; py) fur x py. 55 Informatik II { Sommersemester 1999 56 Veranschaulichung: Merke: Da der Zielwert nicht bekannt ist, mu der f Test, ob die Fehlerschranke schon unterschritten wurde, haug indirekt mittels Berechnung anderer Werte arbeiten. Es gibt keine allgemeine Methode, geeignete Tests fur beliebige Algorithmen zu konstruieren, sondern wie bei Algorithmen selbst ist jedesmal von Neuem Kreativitat gefragt. g z y x ;! Sobald f (x) " 2z gilt, ist x ; py " erreicht. Genaueres zum Thema Behandlung numerischer Fehler: Veranstaltungen zur Numerischen Mathematik. Informatik II { Sommersemester 1999 57 Fallbeispiel aus der Praxis: Rekonstruktion fehler- hafter Nachbarschaften zwischen Flachenelementen im CAD Informatik II { Sommersemester 1999 58 Fehler in den Daten: Fehlerhafte Spalte zwischen Flachenelementen CAD{Modell einer Pumpe: Informatik II { Sommersemester 1999 59 Informatik II { Sommersemester 1999 60 Extrembeispiel fur Datenfehler (gefunden im Innern der Pumpe): Algorithmische Problemstellung: Fehlerhafte Spalte von beabsichtigten O nungen unterscheiden. Einsicht: Es kommen zwar sehr viele fehlerhafte Spalte vor, aber die meisten sind eher schmal (uberwiegend auf den Bildern nicht einmal sichtbar). O nungen hingegen sind eher breit. ;! Idee: Abstandsfunktion fur Paare von Flachenelementen denieren. Schwellwert " > 0 unterscheidet fehlerhafte Spal- te zwischen Flachenelementen von beabsichtigten O nungen. 111 000 111 111 000 000 111 000 111 000 111 000 000 111 Informatik II { Sommersemester 1999 61 Beispiele fur sinnvolle Abstandsfunktionen zwischen Flachenelementen: Minimaler Abstand von irgendeinem Punkt auf einem Element zu irgendeinem Punkt auf dem anderen Element. Durchschnittlicher Abstand von einander "gegenuberliegenden\ Randpunkten. Flache in der Lucke zwischen den einander gegenuberliegenden Randsegmenten. ;! Alles Mae fur den absoluten Fehler. Informatik II { Sommersemester 1999 62 Bonbon\ zum Abschlu: Visualisierung des Ergeb"nisses durch Einfarben von Randern gema Anzahl der anliegenden Flachenelemente Relativer Fehler: " multipliziert mit einem Ma fur die Groe der Flachenelemente (z.B. Flacheninhalt, Durchmesser, Umfang). Unterschied: Relativer Fehler ist von der Skalierung des Modells unabhangig. Informatik II { Sommersemester 1999 63 Informatik II { Sommersemester 1999 64 Erinnerung: Ein Algorithmus heit korrekt ... wenn er bei einer zulassigen Eingabe ... Beachte: Es wird nichts uber das Verhalten des Algorithmus bei nichtzulassigen Eingaben ausgesagt! Konkret: Algorithmus ist auch dann korrekt, wenn er Merke: Informell bedeuten absoluter bzw. relativer Fehler: Die Diskrepanz zwischen Ziel und Ergebnis wird ohne bzw. mit Berucksichtigung der Groe der auftretenden Objekte berechnet. Falls diese Objekte in beliebiger Skalierung auftreten konnen, ist der absolute Fehler kein adaquater Mastab, nur der relative. Informatik II { Sommersemester 1999 bei nichtzulassigen Eingaben absturzt, in Endlosschleife lauft oder sonstigen Blodsinn macht! Prinzip Design{by{Contract: Spezikation ist "Vertrag\ zwischen dem Algorithmus und seinem "Kunden\. Kunde erfullt den Vertrag, wenn er nur zulassige Eingaben macht. Dann (und nur dann!) ist der Algorithmus "vertraglich\ verpichtet, korrekt zu laufen und die korrekte Ausgabe zu liefern. 65 Einfaches Beispiel Design{by{Contract: Mogliche Eingaben: ganze Zahlen n 66 Warum Design{by{Contract? Konkret: Warum nicht einfach im Algorithmus fur n! die Bedingung n > 0 abtesten und im Fall n 0 eine (z.B. Java{Datentyp int). Zulassige Eingaben: n > 0. Gewunschte Ausgabe: n!, d.h. 1 2 3 (n ; 1) n. Fehlermeldung liefern? Mogliche Formen fur Fehlermeldung: Gefahr: "Kunde\ kann leicht seinen Teil des Vertrags vergessen bzw. in komplexeren Fallen unsachgema oder nur unzureichend erfullen. ;! Potentiell undeniertes Programmverhal- "Unmoglicher\ Wert anstelle von n! (z.B. ;1). int faculty (int n) // Liefert n!, falls n>0, sonst -1 Zusatzlicher Boolescher Parameter, der angibt, ob ten sowohl im Algorithmus als auch (falls es uberhaupt soweit kommt) nach Termination des Algorithmus im weiteren Programmverlauf. Ergebnis korrekt ist: int faculty (int n, Boolean resultIsCorrect) // Ergebnis ist n!, falls Oene Frage: Wenn Design{by{Contract so gefahrlich ist | warum dann uberhaupt? Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 67 // resultIsCorrect.valueOf() == true Informatik II { Sommersemester 1999 68 Also: Warum nun Design{by{Contract? 1. Antwort: Wenn Kunde kein Problem hat, den Vertrag zu erfullen, kostet das zusatzliche Abtesten unnotig Laufzeit. Beispiel fur signikanten Ezienzverlust: Eingaben: Liste von Personendaten fur Studierende sowie eine Zahl n. Zulassige Eingaben: Alle Matrikelnummern mussen verschieden voneinander sein. Gewunschte Ausgabe: Der/die Studierende mit Matrikelnummer n (bzw. Meldung "existiert nicht\). Vorgri auf spateren Abschnitt der Vorlesung: Suchen einer Matrikelnummer geht um Groenordnungen schneller als der Test, da alle Matrikelnummern verschieden sind. ;! Design{by{Contract reduziert hier die nur schwierig oder sogar unmoglich zu testen. Beispiel: wieder algorithmenorientierte Problemstellung fur das Newton{Verfahren. Zur Erinnerung: x3 x 2 x1 x0 Bedingungen an die Funktion f : Monotonie und Konvexitat. Laufzeit um Groenordnungen. Informatik II { Sommersemester 1999 Fortsetzung warum Design{by{Contract 2. Antwort: Zulassigkeit der Eingabe ist manchmal 69 Technische Exkursion: Wie eine Funktion wie f an einen Algorithmus wie "Newton\ ubergeben? Idee: ahnlich wie bei der generischen Implementation von sort zuvor. Interface Function denieren: interface Function { double value (double x); } Informatik II { Sommersemester 1999 70 Nun der Newton{Algorithmus selbst: double findZeroUsingNewton (Function f, Function fDerived, NumericErrorChecker checker, double start) { Bei der Gelegenheit ... auch den Test auf "Nullstelle double x = start; while ( ! checker.closeToSomeZero(f,x) ) x = x - f.value(x) / fDerived.value(x); } genau genug erreicht\ durch zusatzlichen Parameter exibel halten: interface NumericErrorChecker { boolean closeToSomeZero (Function f, double x); } Erlauterung: Ruckgabe ist true genau dann, wenn x Nullstelle. Informatik II { Sommersemester 1999 71 Informatik II { Sommersemester 1999 72 Zuruck zum Ausgangspunkt: 2. Antwort auf "warum Fortsetzung warum Design{by{Contract Erinnerung: Behauptung ist, da Zulassigkeit der Eingabe manchmal nur schwierig oder sogar unmoglich zu testen ist. 3. Antwort: Die Menge der zulassigen Eingaben ist Design{by{Contract?\ Konkretes Problem: Wie sollen Monotonie und Kon- vexitat eines Function{Objekts eigentlich gepruft werden? Wenn Funktion nur Methode value bietet, gibt es nicht unbedingt formal fabar. Wieder Beispiel Newton{Verfahren: Verfahren funktioniert auch auf Funktionen f , die nicht die oben formulierten strengen Bedingungen an Monotonie und Konvexitat erfullen. nur eine Moglichkeit: die Funktionswerte fur alle x berechnen. ;! Unrealistisch. "Strohhalm\: Weitere Methoden fur Function, die den Test auf Monotonie und Konvexitat unterstutzen. Leider: keine allgemein anwendbare Idee fur solche Methoden in Sicht. Problem: "Grenzlinie\ zwischen geeigneten und ungeeigneten Funktionen ist weitgehend unbekannt. ;! Jeder Test auf Zulassigkeit der Eingabe Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 73 weist entweder geeignete Funktionen ab oder lat ungeeignete Funktionen durch. 74 Thema 4: Korrekte Algorithmen Einfuhrendes Beispiel: Bisektionsverfahren zur Be- Merke: rechnung einer Nullstelle. Zulassige Eingabe: Stetige Funktion f : R ;! R , reelle Zahlen a < b, so da entweder f (a) < 0 und f (b) > 0 oder f (a) > 0 und f (b) < 0 ist. Gewunschte Ausgabe: Approximation des x{Wertes einer Nullstelle von f im Intervall [a; b]. Die Einschrankung der Korrektheit auf zulassige Eingaben (Design{by{Contract) ist potentiell gefahrlich. Aus verschiedenen Grunden mu Design{by{ Contract dennoch haug angewandt werden: { algorithmische Ezienz, { Test auf Zulassigkeit der Eingabe potentiell unmoglich, { potentiell uberhaupt keine befriedigende Spezikation zum Abtesten der Zulassigkeit von Eingaben verfugbar. f(a) b a f(b) Informatik II { Sommersemester 1999 75 Informatik II { Sommersemester 1999 76 Vorarbeit zur Vereinfachung: Funktion differentSign testet ab, ob zwei reelle Zahlen x und y unterschiedliches Vorzeichen haben. Algorithmischer Ansatz (der Einfachheit halber nur mit absolutem Fehler): double left_end = a; double right_end = b; while ( left_end + 2*epsilon < right_end ) { double middle = ( left_end + right_end ) / 2; if ( differentSign ( f(left_end), f(middle) ) ) right_end = middle; else left_end = middle; } return ( left_end + right_end ) / 2; boolean differentSign ( double x, double y ) { if ( x > 0 && y < 0 ) return true; if ( x < 0 && y > 0 ) return true; return false; } Informatik II { Sommersemester 1999 77 Informatik II { Sommersemester 1999 Veranschaulichung: a 1 3 42 78 ... while ( left_end + 2*epsilon < right_end ) { double middle = ( left_end + right_end ) / 2; if ( differentSign ( f(left_end), f(middle) ) ) right_end = middle; else left_end = middle; } ... b Schleifeninvarianten: Am Anfang und Ende jedes Schleifendurchlaufs gilt left_end < right_end differentSign(f(left_end),f(right_end)) == true Konsequenz daraus (zusammen mit der Stetigkeit von f ): Am Anfang und Ende jedes Schleifendurchlaufs liegt mindestens eine Nullstelle von f im momentanen Intervall [left Informatik II { Sommersemester 1999 79 end,right end]. Informatik II { Sommersemester 1999 80 Schleifenvariante: Nach k Durchlaufen der Merke: Schleife gilt (Rundungsfehler vernachlassigt): right end ; left end Ein nichttrivialer Algorithmus besteht "im we- = b 2;k a Konsequenz: Programm terminiert, sobald b;a 2" 2k ;! Programm terminiert nach b ; a log2 2 " Durchlaufen durch die Schleife. Informatik II { Sommersemester 1999 81 Wichtige Einsicht: Korrektheit des Algorithmus ist nun beweisbar. Erinnerung: Ein Algorithmus heit korrekt bzgl. einer Spezikation einer algorithmischen Problemstellung, wenn er bei einer nach dieser Spezikation zulassigen Eingabe nur wohldenierte Schritte macht, terminiert und ein gema Spezikation korrektes Ergebnis liefert. sentlichen\ aus einer oder mehreren Schleifen (die auch ineinandergeschachtelt sein konnen). Ausnahme: rekursive Algorithmen (spater). Eine Schleifeninvariante ist eine Aussage uber die Werte von Variablen, die in jedem Durchlauf gultig ist. Eine Schleifenvariante ist eine Aussage uber die A nderung von Variablenwerten von Durchlauf zu Durchlauf. Zur Formulierung einer Invariante oder Variante gehort unbedingt dazu, an welcher Stelle der Schleife genau sie gultig sein soll (meist Anfang/Ende). Informatik II { Sommersemester 1999 82 Nun konkreter Korrektheitsbeweis fur das Bisektionsverfahren: Oensichtlich keine undenierten Schritte. Erinnerung: Schleife terminiert nach maximal dlog2( b2;"a )e Durchlaufen. ;! Algorithmus als Ganzes terminiert. Schleifeninvariante ;! Auch bei Termination liegt immer noch eine Nullstelle zwischen left end und right end. ;! Ruckgabewert der Bisektionsfunktion ist hochstens " von irgendeiner Nullstelle entfernt. ;! Ruckgabewert ist korrekt gema absolutem Fehlerma. Informatik II { Sommersemester 1999 83 Informatik II { Sommersemester 1999 84 Weiteres Beispiel: Fibonacci{Zahlen fib(1) = fib(2) = 1, fib(n) = fib(n ; 1) + fib(n ; 2) fur n > 2. Notation: xi, yi und zi seien die Werte von x, y und z unmittelbar nach der Addition "z = x + y\ im Durchlauf Nr. i durch die Schleife. Drei Schleifeninvarianten: xi = fib(i ; 2), yi = fib(i ; 1), zi = fib(i). ;! Es gilt z = fib(n) nach dem allerletzten ;! 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... Algorithmus in Java: int fibonacci ( int n ) // Voraussetzung nach // "Design-by-Contract": n > 0. { if ( n <= 2 ) return 1; int x; int y = 1; int z = 1; for ( int i = 3; i <= n; i++ ) { x = y; y = z; z = x + y; } return z; } Informatik II { Sommersemester 1999 Durchlauf. ;! Ruckgabewert von bonacci ist oensichtlich korrekt. Beachte: Sowohl die Scheifenvarianten selbst als auch die Korrektheit des Algorithmus auf Basis der Schleifeninvarianten lassen sich wesentlich einfacher durchschauen und nachvollziehen als der Algorithmus als Ganzes. Psychologischer Hintergrund: Komplexe, nichtlineare Ablaufe sind in eine Folge von Schnappschussen zerlegt, die Schritt fur Schritt durchdacht werden konnen. 85 Erinnerung: Algorithmus mu auch wohldeniert laufen und terminieren! Einzige Gefahr fur wohldenierten Lauf bei diesem Algorithmus: Arithmetischer U berlauf bei der Addition. Beobachtung: Falls fib(n) mit Java{Datentyp int Informatik II { Sommersemester 1999 Termination: Eigentlich trivial bei reinen Zahlscheifen wie hier: for ( int i = 3; i <= n; i++ ) Achtung: Frage nicht zu fruh als erledigt betrachten! darstellbar ist, kann auch bei den Zwischenergebnissen kein U berlauf passieren, da alle Zwischenergebnisse im Bereich [0; : : : ; fib(n)] liegen. Beliebte Tippfehler: Maximal darstellbare Zahl: 231 ; 1 = 2:147:483:647. ;! Fur n 46 lauft der Algorithmus wohldeniert. Informatik II { Sommersemester 1999 87 86 for ( int i = 3; i >= n; i++ ) ;! falschlich sofortiger Abbruch fur n > 3. for ( int i = 3; i <= n; i-- ) for ( int i = 3; ; i++ ) ;! arithmetischer U berlauf. for ( int i = 3; i <= n; ) ;! Endlosschleife fur n 3. Informatik II { Sommersemester 1999 88 Mathematische Exkursion: Korrektheit von Algorith- Merke: men und vollstandige Induktion. Aus gut gewahlten Schleifeninvarianten und Standardbeispiel zur Erinnerung: -varianten lat sich die Idee eines Algorithmus verstehen und seine Korrektheit im Prinzip auch beweisen. Faustregel: { Schleifenvarianten sind gut gewahlt, wenn aus ihnen leicht Termination ersichtlich ist. { Schleifeninvarianten sind gut gewahlt, wenn aus der Aussage der Schleifeninvarianten fur den allerletzten Durchlauf durch die Schleife unmittelbar folgt, da die Ausgabe des Algorithmus korrekt ist. Allerdings mu noch gepruft werden, ob alle Details der Implementation wirklich mit dem "gedachten\ Algorithmus ubereinstimmen. Informatik II { Sommersemester 1999 Beobachtungen: i=1 i = n(n2+ 1) Behauptung ist wahr fur n = 1. Falls Behauptung fur irgendein n wahr ist, dann auch fur m := n + 1, denn: m X i=1 i= n X i=1 i + (n + 1) = n(n + 1) + (n + 1) ! 2 = n(n + 1) +2 2(n + 1) = (n + 1)(2 n + 2) = m(m2+ 1) 89 Idee der vollstandigen Induktion: Behauptung ist wahr fur n = 1 ;! auch fur n = 2 ;! auch fur n = 3 ;! auch fur n = 4 ::: ;! auch fur n = 3:796:541 ::: Informatik II { Sommersemester 1999 90 Merke: Schleifeninvarianten werden grundsatzlich Gliederung eines Beweises mit vollstandiger Induktion: Induktionsverankerung: Beweise, da die Behaup- tung fur n = 1 wahr ist. Induktionsschritt: Beweise, da die Behauptung fur n + 1 wahr ist, unter der Voraussetzung, da sie fur n wahr ist. Informatik II { Sommersemester 1999 n X 91 durch vollstandige Induktion bewiesen (auch dann, wenn man diese vollstandige Induktion nicht explizit ausformuliert). Die Gultigkeit der Schleifeninvarianten im ersten Durchlauf ist gerade die Induktionsverankerung. Die Korrektheit der Verankerung ergibt sich aus den Initialisierungen vor der Schleife. Der Induktionsschritt beweist die Gultigkeit der Schleifeninvarianten fur den Durchlauf Nr. k +1 unter der Voraussetzung, da die Schleifeninvarianten fur den Durchlauf Nr. k wahr sind. Informatik II { Sommersemester 1999 92 Abschlieender Ausblick: Es gibt algorithmische Problemstellungen, fur die mit mathematischer Strenge bewiesen werden kann, da es keinen Losungsalgorithmus geben kann. Dazu gehort zum Beispiel die algorithmische Problemstellung prufe ob ein beliebig gegebenes "Java{Programm korrekt ist\. Details: Vorlesung Theoretische Informatik Unuberwindliche Hurde: Die entscheidenden Schleifeninvarianten und -varianten konnen nicht algorithmisch aus dem Quelltext rekonstruiert werden. Moglicher Ausweg in der Zukunft: neue Programmiersprachen, die die explizite Angabe aller notwendigen Schleifeninvarianten und -varianten vom Programmierer erzwingen. Informatik II { Sommersemester 1999 93 Entwurf von Algorithmen in Sicht. ;! Immer wieder Kreativitat erforderlich. Grundidee fur eine mogliche Herangehensweise: Erst die zentralen Schleifeninvarianten und -varianten ausdenken. Daraus dann den Algorithmus selbst entwickeln. Fallbeispiel: zwei verschiedene Algorithmen fur das Sortierproblem. Eingabe: Array A von n Werten eines Datentyps, auf denen eine Sortierreihenfolge "\ deniert ist. Ergebnis: A ist sortiert gema "\. Informatik II { Sommersemester 1999 94 Vollstandiger Algorithmus in Java: Algorithmus I: "Selection{Sort\ (Sortieren durch direktes Auswahlen) int indexOfMin (Object[] A, int first_index, Comparator cmp) { int index = first_index; for ( int i=first_index+1; i<A.length; i++ ) if ( cmp.is_less_than ( A[i], A[index] ) ) index = i; return index; } Einfache Idee fur eine Schleifeninvariante: Nach k Durchlaufen stehen in A[0]; : : : ;A[k-1] die gem a Sortierreihenfolge korrekten Elemente. void swapComponents (Object[] A, int index1, int index2) { Object x = A[index1]; A[index1] = A[index2]; A[index2] = x; } ;! Algorithmisches Vorgehen ist (fast) oensichtlich: Vertausche A[k-1] mit minfA[k-1]; : : : ; A[A.length-1]g im k{ten Durchlauf. Informatik II { Sommersemester 1999 Thema 5: Entwurf von Algorithmen Grundproblem: Kein "Algorithmus\ zum void sort (Object[] A, Comparator cmp) { for ( int i=0; i<A.length; i++ ) { int index = indexOfMin (A, i, cmp); swapComponents (A[i], A[index]); } } 95 Informatik II { Sommersemester 1999 96 Algorithmus II: "Mergesort\ Zahlenbeispiel: (Sortieren durch Verschmelzen) Schleifeninvariante: 21 17 41 67 41 12 15 23 88 9 27 44 18 11 4 36 Nach k Durchlaufen sind jeweils 2k aufeinanderfolgende Elemente untereinander korrekt sortiert. 21 17 17 21 Etwas genauer formuliert: Sei n :=A.length. Fall, da n eine Zweierpotenz ist, d.h. n = 2m fur ein m 2 N . Das Intervall f0; : : : ; n ; 1g wird fur den k{ten Durchlauf in 2m;k Abschnitte der Lange 2k zerlegt. Die Reihenfolge der Elemente innerhalb eines dieser Abschnitte soll am Ende des k{ten Durchlaufs der Sortierreihenfolge entsprechen. 97 Oenes Problem: ezient zwei sortierte Sequenzen der Lange 2k;1 zu einer sortierten Sequenz der Lange 2k verschmelzen. ;! Eigenstandiges algorithmisches Problem. Beobachtung: Algorithmus fur's Verschmelzen wird wohl im Kern wieder eine Schleife sein. ;! Wieder uber Schleifeninvarianten und -varianten nachdenken. 41 67 12 41 15 23 12 15 23 41 12 15 17 21 23 41 41 67 4 23 88 9 9 88 27 44 18 27 44 9 27 44 88 11 11 18 4 36 4 36 4 11 18 36 4 9 11 18 27 36 44 88 9 11 12 15 17 18 21 23 27 36 41 41 44 67 88 Informatik II { Sommersemester 1999 98 Mogliche Umsetzung: Ein Hilfsarray der Lange 2k wird angelegt. Die Elemente der beiden zu verschmelzenden Teil- sequenzen werden Schritt fur Schritt in sortierter Reihenfolge in das Hilfsarray kopiert. Dann wird der Inhalt des Hilfsarrays in die 2k Komponenten im eigentlichen Array zuruckkopiert. Idee fur sortierte Kopie in das Hilfsarray: Idee fur Schleifeninvariante: { Zwei aktuelle Indizes j1 und j2 zeigen an, bis zu welchem Element jede der beiden Teilsequenzen schon kopiert wurde. { Das kleinere der beiden durch j1 und j2 angezeigten Elemente wird jeweils als nachstes kopiert. { Bei zwei gleichen Elementen: egal. Nach i Durchlaufen sind die ersten i der insgesamt 2k Positionen der Sequenz mit den dort hingehorenden Elementen besetzt. Informatik II { Sommersemester 1999 67 41 12 15 17 21 41 67 Zur Vereinfachung betrachten wir zunachst nur den Informatik II { Sommersemester 1999 41 99 Informatik II { Sommersemester 1999 100 Zahlenbeispiel: Fortsetzung Zahlenbeispiel: j1 j2 17 21 41 67 12 15 23 41 j1 j2 17 21 41 67 12 15 23 41 j1 j2 17 21 41 67 12 15 23 41 j2 j1 17 21 41 67 12 15 23 41 j1 17 21 41 67 j1 i j2 12 15 23 41 i j1 j2 17 21 41 67 12 15 23 41 i j1 12 15 17 21 41 67 17 21 41 67 i 12 15 17 21 23 41 j2 i 12 15 17 21 23 41 41 j2 12 15 23 41 i 12 15 17 21 23 41 41 67 i 12 15 17 21 101 Notation: Sei 0; : : : ; 2k;1 ; 1 der Indexbereich der beiden Teilsequenzen sowie 0; : : : ; 2k ; 1 der Indexbereich der "verschmolzenen\ Sequenz. Schleifeninvarianten nach dem h{ten Durchlauf: i = j1 + j2 = h. Die Elemente 0; : : : ; j1 ; 1 der ersten und die Elemente 0; : : : ; j2 ; 1 der zweiten Teilsequenz sind in sortierter Reihenfolge an den Indizes 0; : : : ; i ; 1 der verschmolzenen Sequenz gespeichert. Element j1 der ersten Teilsequenz ist groer/gleich Element j2 ; 1 der zweiten Teilsequenz. Element j2 der zweiten Teilsequenz ist analog groer/gleich Element j1 ; 1 der ersten Teilsequenz. Informatik II { Sommersemester 1999 12 15 17 21 23 12 15 23 41 j1 i 12 15 17 i 12 15 23 41 12 Informatik II { Sommersemester 1999 j2 17 21 41 67 103 Informatik II { Sommersemester 1999 102 Fehlt noch: Der Fall, da n keine Zweierpotenz ist. Notation: Sei 2m die kleinste Zweierpotenz mit n 2m. Erste mogliche Vorgehensweise: Hilfsarray mit 2m Elementen anlegen. Werte von A in das Hilfsarray kopieren. Rest des Hilfsarrays mit 2m ; n "Dummy{Werten\ auullen. Obigen Sortieralgorithmus auf das Hilfsarray anwenden. Alle "Nicht{Dummy{Werte\ aus dem Hilfsarray in sortierter Folge zuruckkopieren. Informatik II { Sommersemester 1999 104 Zahlenbeispiel mit "Dummy{Wert\ 0: Zweite mogliche Vorgehensweise: In jedem Durchlauf ist potentiell die letzte Teilsequenz unvollstandig und wird gesondert, aber analog behandelt. 21 -8 41 67 41 12 -3 23 88 0 27 21 17 41 67 41 12 15 23 88 9 27 21 -8 41 67 41 12 -3 23 88 0 27 0 0 0 0 21 17 0 17 21 Sortieren -3 -8 0 0 0 0 0 41 67 41 12 15 41 67 17 21 41 67 0 12 21 23 27 41 41 67 88 12 41 15 23 12 15 23 41 12 15 17 21 23 41 41 67 -3 -8 0 12 21 23 27 41 41 67 88 Informatik II { Sommersemester 1999 9 9 88 27 27 9 27 88 9 27 88 9 12 15 17 21 23 27 41 41 67 88 105 Weiteres, ahnlich gelagertes Fallbeispiel: Informatik II { Sommersemester 1999 106 Nun Ziel: Fur Mengen A und B mit einer solchen Ordnung "\ einen massiv ezienteren Algorithmus entwickeln. Schnittmenge berechnen Gegeben: Zwei endliche Mengen A und B . Gesucht: Schnitt A \ B . A 23 88 ;! Einschrankung auf geordnete Mengen A und B ist weiteres sinnvolles Beispiel fur algo- rithmenorientierte Denitionen von algorithmischen Problemstellungen (vgl. Thema 1 der Vorlesung). B Primitive Idee: Alle Elemente von A durchgehen und nachschauen, ob das Element jeweils in B enthalten ist. ;! jAj jB j Tests auf Gleichheit von Elementen. Annahme zur Vereinfachung: A und B sind "richtige\ Mengen, d.h. alle Elemente von A sind paarweise verschieden (ebenso alle Elemente von B untereinander). Hilfreiche Einsicht: In der Praxis haben A und B meist gleichen Elementtyp, und man kann meist eine Ordnung "\ auf diesem Typ denieren (bzw. ist sogar schon vordeniert). Informatik II { Sommersemester 1999 107 Informatik II { Sommersemester 1999 108 Erste Idee fur Schleifeninvarianten: Zwei Indizes i und j durchlaufen A und B so, da Notation: A = fa0; a1; : : : ; am;1g mit a0 a1 am;1. immer ai;1 bj und bj;1 ai gilt und alle Elemente von Ai \ Bj schon gefunden und B = fb0; b1; : : : ; bn;1g mit b0 b1 bn;1. ausgegeben sind, aber noch kein Element von (A n Ai) \ (B n Bj ). Ai := fa0; : : : ; ai;1g fur i 2 f0; : : : ; mg (insbesondere A0 = ; und Am = A). Ai Bj := fb0; : : : ; bj;1g fur j 2 f0; : : : ; ng (insbesondere B0 = ; und Bn = B ). i A 2 3 B 2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 5 7 11 13 17 19 23 29 31 37 41 43 47 53 j Bj Informatik II { Sommersemester 1999 109 Beobachtung: Aus der ersten Schleifeninvariante folgt Ai \ (B n Bj ) = Bj \ (A n Ai) = ;. Konsequenz: A \ B = (Ai \ Bi) [ ((A n Ai) \ (B n Bj )), d.h. der Algorithmus "erwischt\ tatsachlich alle Elemente von A \ B . Informatik II { Sommersemester 1999 Einfache Umsetzung: int i int j while { if { A B 2 2 3 5 5 = 0; = 0; ( i < m && j < n ) ( A[i] == B[j] ) System.out.println ( A[i] ); i++; j++; } else if ( A[i] < B[j] ) i++; else // A[i] > B[j] j++; } Schleifenvariante: In jedem Durchlauf wird i oder j (oder beide) um 1 erhoht. Ai 110 i Ai 7 11 13 17 19 23 29 31 37 41 43 47 53 i A 2 3 5 B 2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 7 11 13 17 19 23 29 31 37 41 43 47 53 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 Bj j j Bj Informatik II { Sommersemester 1999 111 Informatik II { Sommersemester 1999 112 Beachte: Erste Idee zu Schleifeninvarianten sagt nichts uber den Fall i = m oder j = n aus. Konkretisierte Schleifeninvarianten: Vor und nach jedem Schleifendurchlauf existieren zwei aktuelle Indizes i 2 f0; : : : ; mg und j 2 f0; : : : ; ng, so da ai;1 bj und bj;1 ai im Falle i < m; j < n gilt und alle Elemente von Ai \ Bj schon gefunden und ausgegeben sind, aber noch kein Element von (A n Ai) \ (B n Bj ). Korrektheitsbeweis: Termination: Aufgrund der Schleifenvariante nach maximal m + n Durchlaufen. Wohldeniertheit: Durch die Abbruchbedingung der while{Schleife ist garantiert, da nur auf existierende Komponenten von A und B zugegrien wird. Korrektes Ergebnis: Am Ende des Algorithmus gilt i = m oder j = n (oder beides). ;! A n Ai = ; oder B n Bj = ;. ;! (A n Ai) \ (B n Bj ) = ;. ;! Ai \ Bj = A \ B . ;! Die Schleifeninvariante beweist, da am Ende genau A \ B ausgegeben worden ist. Frage: Wo wird eigentlich die Annahme gebraucht, da alle Elemente paarweise verschieden sind? Informatik II { Sommersemester 1999 113 Antwort: in der Schleifeninvariante. Gegenbeispiel fur den Fall, da die Annahme nicht zutrit: 2 3 B 2 5 8 11 14 17 20 20 26 29 32 35 38 41 44 47 50 53 56 Bj Hatte man selbst bei der Formulierung des Algorithmus und beim Korrektheitsbeweis an die Annahme und ihre wesentliche Bedeutung fur die Korrektheit der Schleifeninvariante gedacht!? i A 5 114 Unangenehme Frage: und nach jedem Schleifendurchlauf gibt es "Vor aktuelle zwei Indizes i 2 f0; : : : ; mg und j 2 f0; : : : ; ng, so da ai;1 bj und bj;1 ai im Falle i < m; j < n gilt.\ Ai Informatik II { Sommersemester 1999 7 11 13 17 20 20 29 31 37 41 43 47 53 j ;! Nach dem nachsten Vorwartsschritt wird die Schleifeninvariante verletzt. Informatik II { Sommersemester 1999 115 Informatik II { Sommersemester 1999 116 Thema 6: Rekursive Algorithmen Beobachtung: Viele Funktionen kann man Merke: Die Schleifenvarianten und -invarianten eines iterativ und rekursiv denieren. Algorithmus sind in gewisser Weise seine "Essenz\. Entwurf von Algorithmen ist (und bleibt wohl auch) eine kreative Tatigkeit, fur die es kein Kochrezept gibt. Oft ist es einfacher, eine intuitive Idee fur die algorithmische Vorgehensweise zuerst in eine solche "Essenz\ umzusetzen und daraus dann den eigentlichen Algorithmus zu konstruieren. Beispiel: Fakultat. Iterative Denition: n! = 1 2 (n ; 1) n. Rekursive Denition: n! = 1 fur n = 1 bzw. n! = n (n ; 1)! fur n > 1. Iterative Denition implementieren: Insbesondere hat man dabei den Korrektheits- int faculty ( int n ) { int result = 1; for ( int i = 2; i <= n; i++ ) result *= i; return result; } beweis fur den Algorithmus gleich mitkonstruiert. Informatik II { Sommersemester 1999 117 Nun rekursive Denition implementieren: Informatik II { Sommersemester 1999 118 Experiment: int faculty ( int n ) { if ( n == 1 ) return 1; return n * faculty ( n - 1 ); } Beobachtung: Es spricht prinzipiell zunachst einmal nichts dagegen, da eine Methode auch "sich selbst\ aufrufen kann. public static void myRecursiveMethod ( int n ) { if ( n == 0 ) return; System.out.print ( n ); System.out.print ( " " ); myRecursiveMethod ( n - 1 ); System.out.print ( n ); System.out.print ( " " ); } ... myRecursiveMethod ( 5 ); Ausgabe: 5 4 3 2 1 1 2 3 Frage: Was geht da vor sich!? Informatik II { Sommersemester 1999 119 Informatik II { Sommersemester 1999 4 5 120 Erklarung: Wann immer eine Methode aufgerufen wird, wird intern neuer Speicherplatz fur die Daten des Aufrufs angelegt (u.a. fur jeden Parameter). Am Ende des Aufrufs wird der Speicherplatz wieder freigegeben, Es sind immer nur die Daten des letzten Aufrufs sichtbar. ;! Wahrend des 5. und tiefsten rekursiven Aufrufs von myRecursiveMethod im Beispiel gibt es insgesamt 5 verschiedene, vollig voneinander unabhangige Speicherplatze mit Namen n. 5 4 3 2 1 n n n n Informatik II { Sommersemester 1999 void f ( int n ) { System.out.println ( n ); f ( n - 1 ); } Ergebnis: Nach Ausgabe eines gewissen Wertes n gibt es Programmfehler! Erlauterung: Fur die Gesamtdaten aller Methodenaufrufe eines Daten zum 1. 2. 3. 4. 5. rekursiven Aufruf n Vorsicht: Rekursion ohne Abbruch! 121 Abschreckendes Beispiel: Fibonacci{Zahlen Programms ist nur ein gewisser kleiner Speicherplatz reserviert. Bei einer Rekursion ohne Abbruch wird diese Grenze naturlich irgendwann uberschritten. Informatik II { Sommersemester 1999 122 Frage: Was ist das Problem? Antwort: Die ganzen Zwischenergebnisse fib(1), fib(2); : : : ; fib(n) werden immer und immer wieder Erinnerung: fib(1) = fib(2) = 1, fib(n) = fib(n ; 1) + fib(n ; 2) fur n > 2. neu berechnet (und wieder vergessen). Umsetzung als rekursive Methode: fib (6) int fibonacci ( int n ) { if ( n <= 2 ) return 1; else return fibonacci (n-1) + fibonacci (n-2); } fib (5) fib (4) Beobachtung: Fur n = 30 wird die Laufzeit schon spurbar. Fur n = 40 dauert es eeeeewig. fib (3) Kontrast: Beim iterativen Algorithmus aus Thema 4 der Vorlesung ist das Ergebnis auch bei n = 40 sofort da. Informatik II { Sommersemester 1999 123 fib (2) fib (2) fib (4) fib (3) fib (2) fib (1) fib (3) fib (2) fib (2) fib (1) fib (1) Informatik II { Sommersemester 1999 124 n Konkret: Notation: g(n) Gesamtzahl der Aufrufe von fibonacci f ur Eingabe n. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Beobachtung: g(1) = g(2) = 1, g(n) = g(n ; 1) + g(n ; 2) + 1 fur n > 2. Einsicht: g(n) = 2 fib(n) ; 1 fur n 2. Begrundung mit vollstandiger Induktion: n = 2: Oensichtlich. n > 2: g(n) = g(n ; 1) + g(n ; 2) + 1 = [2 fib(n ; 1) ; 1] + [2 fib(n ; 2) ; 1] + 1 = 2 fib(n) ; 1. Informatik II { Sommersemester 1999 g(n) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 1 1 3 5 9 15 25 41 67 109 177 287 465 753 1219 20 6:765 13:529 30 832:040 1:664:079 ::: ::: ::: ::: ::: ::: ::: ::: ::: 40 102:334:155 204:668:309 125 Kontrast: Beim iterativen Algorithmus wurde jedes der n Zwischenergebnisse genau einmal berechnet. Erinnerung (Vorlesungsthema 4): int fibonacci ( { if ( n <= 2 return 1; int x; int y = 1; int z = 1; for ( int i { x = y; y = z; z = x + } return z; } fib(n) Informatik II { Sommersemester 1999 126 ... Wozu eigentlich Rekursion!? Antwort: Rekursive Algoritmen sind oft sehr viel einfacher und auch naher an den dahinterstehenden abstrakten Ideen. Beispiel: Mergesort (vgl. Vorlesungsthema 5) int n ) ) 21 17 41 67 41 12 15 23 88 9 27 44 18 11 4 36 21 17 41 67 41 12 41 67 12 41 15 23 88 9 27 44 18 11 4 36 = 3; i <= n; i++ ) 17 21 17 21 41 67 y; 15 23 12 15 23 41 12 15 17 21 23 41 41 67 4 9 88 27 44 9 27 44 88 11 18 4 36 4 11 18 36 4 9 11 18 27 36 44 88 9 11 12 15 17 18 21 23 27 36 41 41 44 67 88 Frage: Wozu dann eigentlich Rekursion??? Informatik II { Sommersemester 1999 127 Informatik II { Sommersemester 1999 128 Rekursive Formulierung: void sortRecursively ( Object[] A, Comparator cmp, int first, int last ) { if ( first == last ) return; int middle = ( first + last ) / 2; sortRecursively ( A, cmp, first, middle ); sortRecursively ( A, cmp, middle+1, last ); merge ( A, cmp, first, middle, last ); } void sort ( Object[] A, Comparator cmp ) { sortRecursively ( A, cmp, 0, A.length-1 ); } Abstrakte Idee von Mergesort: Zerlege die zu sortierende (Teil-)Sequenz in zwei Teilsequenzen durch ungefahre Halbierung. Sortiere beide Teilsequenzen in sich. Verschmelze die nun sortierten zwei Teilsequenzen zu einer insgesamt sortierten. ;! Rekursiver Algorithmus ist fast schon die wortliche Umsetzung dieser abstrakten Idee. Erlauterung: Methode merge ist hier ausgelassen worden und soll das Verschmelzen der sortierten Teilsequenzen A[left]...A[middle] und A[middle+1]...A[last] zu einer sortierten Teilsequenz A[first]...A[last] leisten. ;! Vgl. Thema 5 der Vorlesung. Informatik II { Sommersemester 1999 129 U blicher Trick: Den eigentlich rekursiven Algorithmus in eine eigene Methode auslagern. Warum: Die Rekursion basiert haug auf zusatzlichen Parametern, die in der eigentlichen algorithmischen Problemstellung nur implizit auftreten. Beispiel von oben: Anfang und Ende der zu sortierenden Teilsequenz. void sortRecursively ( Object[] A, Comparator cmp, int first, int last ) { ... } Informatik II { Sommersemester 1999 130 Weiteres Beispiel: Formalsprachliche Ausdrucke auswerten. Konkretes Beispiel: 4 + (3 + 2) (4=(6 ; (8 4 + (2 ; 3)))) + 4 * + 3 / 2 - 4 6 + void sort ( Object[] A, Comparator cmp ) { sortRecursively ( A, cmp, 0, A.length-1 ); } 8 Informatik II { Sommersemester 1999 - * 131 Informatik II { Sommersemester 1999 4 2 3 132 Umsetzung: Abstrakte Idee fur rekursive Auswertung: Falls Ausdruck eine einzelne Zahl... ;! Wert des Ausdrucks = Zahl. Falls ganzer Ausdruck in Klammern... ;! Vergi die Klammern. In jedem anderen Fall sollte es mindestens einen binaren Operator (also Plus, Minus, Mal, Durch) auf hochster Stufe auerhalb aller Klammern geben. { Falls es mindestens ein Plus oder Minus auf hochster Stufe gibt: Brich den Ausdruck am linkesten Plus oder Minus auf ("Punkt vor Strich\!). { Sonst: Brich den Ausdruck am linkesten Mal oder Durch auf. Informatik II { Sommersemester 1999 Methode evaluate 133 branched: public double evaluate ( String expr ) throws IllFormedExpression { if ( isDoubleNumber (expr) ) return convertToDouble (expr); int index; double value; if ( plusOrMinusOnHighestLevel (expr) ) { index = findFirstPlusOrMinusOnHighestLevel (expr); value = evaluate_branched ( expr, index ); } else if ( timesOrDivOnHighestLevel (expr) ) { index = findFirstTimesOrDivOnHighestLevel (expr); value = evaluate_branched ( expr, index ); } else if ( expr[0]=='(' && expr[expr.length()-1]==')' ) { String realExpr = expr.substring ( 1, expr.length()-2 ); value = evaluate ( realExpr ); } else throw new IllFormedExpression(); return value; } Informatik II { Sommersemester 1999 134 Weitere zu leistende Vorarbeiten fur eine solche Umsetzung auf hoher Abstraktionsebene (hier ausgelassen): public double evaluate_branched ( String expr, int index ) throws IllFormedExpression Test ob expr eine einzelne reelle Zahl ist: { String expr1 = expr.substring (0,index-1); String expr2 = expr.substring (index+1,expr.length()-1); double value1 = evaluate (expr1); double value2 = evaluate (expr2); char operator = expr[index]; if ( operator == '+' ) return value1 + value2; if ( operator == '-' ) return value1 - value2; if ( operator == '*' ) return value1 * value2; if ( operator == '/' ) return value1 / value2; boolean isDoubleNumber (String expr) Berechnung dieser reellen Zahl: double convertToDouble (String expr) Test ob es auf hochster Stufe ein Plus oder Minus gibt (timesOrDivOnHighestLevel analog): double plusOrMinusOnHighestLevel (String expr) } Beobachtung: Zwei Methoden konnen sich auch ge- genseitig rekursiv aufrufen. Falls ja, Lieferung des Index des "linkesten\ Plus oder Minus (findFirstTimesOrDivOnHighestLevel analog): int findFirstPlusOrMinusOnHighestLevel (String expr) Informatik II { Sommersemester 1999 135 Informatik II { Sommersemester 1999 136 Weitere Zusatzarbeit: Exception{Klasse IllFormedExpression zur Anzeige, da der Ausdruck in expr nicht den Regeln entspricht. Korrektheit rekursiver Algorithmen Erinnerung: Hauptkonzept bei iterativen Algorithmen waren Schleifenvarianten und Schleifeninvarianten. ;! Korrektheitsbeweis durch vollstandige In- duktion uber die Anzahl der Schleifendurchlaufe. Rekursiver Fall: Frage: Klingt das alles etwa kompliziert? Wieder mittels vollstandiger Induktion. Nun aber uber die Rekursionsparameter. Antwort: Schon moglich. Eine iterative Formulierung ware aber wohl massiv komplizierter! Informatik II { Sommersemester 1999 137 Beispiel Mergesort: Methode sort als rekursive Formulierung von Mer- gesort lost das Problem oensichtlich korrekt, sofern Hilfsmethode sortRecursively korrekt ist. Rekursionsinvariante: Methode sortRecursively lost das Problem fur n 1 zu sortierende Elemente korrekt. Rekursionsvariante: Bei jedem rekursiven Aufruf wird die Anzahl der zu sortierenden Elemente verkleinert. ;! Endliche maximale Rekursionstiefe. Informatik II { Sommersemester 1999 Rekursionsinvariante: Methode 138 sortRecursively lost das Problem korrekt, wenn Unterprogramm merge korrekt ist und sortRecursively das Problem fur beliebige m < n zu sortierende Elemente korrekt lost. ;! Induktionsschritt. Beobachtung: Korrektheit von Induktionsanfang und Induktionsschritt ergeben sich (fast) trivial aus der rekursiven Beschreibung von Mergesort (vorausgesetzt, merge ist korrekt). Beweise der Rekursionsvariante: In diesem Fall trivial. ;! Nur Invariante zu betrachten. Informatik II { Sommersemester 1999 139 Informatik II { Sommersemester 1999 140 Beobachtung: Jeder iterative Algorithmus lat sich auf einfache Weise in einen rekursiven umformulieren. Beispiel Auswertung von Ausdrucken: Rekursionsvariante: Bei jedem rekursiven Aufruf verringert sich die Anzahl der Zeichen im Ausdruck. ;! Endliche Rekursionstiefe. Iterativer Algorithmus: Rekursionsinvariante: Ein Ausdruck mit n Zeichen wird korrekt behandelt. { Induktionsanfang: Korrektheit der Methoden isDoubleNumber und convertToDouble. { Induktionsschritt: evaluate is korrekt fur Ausdrucke mit n > 1 Zeichen, wenn das Ergebnis von evaluate fur einen beliebigen Ausdruck mit weniger als n Zeichen korrekt ist. Beobachtung: Unter der Annahme, da die ausgelassenen Hilfsmethoden korrekt sind, sind Induktionsanfang und Induktionsschritt wieder (fast) trivial. Informatik II { Sommersemester 1999 Idee am einfachen Beispiel: 141 void iteratively ( int n ) { for ( int i = 0; i <= n; i++ ) System.out.println (i); } Rekursiv derselbe Eekt: void recursively ( int n ) { if ( n < 0 ) return; recursively ( n - 1 ); System.out.println (n); } Informatik II { Sommersemester 1999 142 Thema 7: Asymptotische Ezienz von Algorithmen Merke: Fur jedes Problem, fur das es iterative Algo- Naive\ Denition: Die Ezienz eines Algorithmus "besagt, welche Laufzeit er bis zur Termination ver- rithmen gibt, gibt es auch rekursive Algorithmen. Neben den rekursiven Algorithmen, die man direkt aus den iterativen konstruieren kann, gibt es bei vielen Problemstellungen auch weitere rekursive Algorithmen, die einfacher und intuitiver als jeder iterative Algorithmus sind. Auch der Korrektheitsbeweis ist dann meist einfacher und intuitiver. Allerdings sind solche rekursiven Algorithmen haug (nicht immer!) weniger ezient als die ezientesten iterativen. braucht. Problem: Diese Denition von Ezienz hangt ab von der gewahlten Programmiersprache, der gewahlten Plattform (Hardware, Betriebssystem und Compiler), den anderen momentan auf dem System laufenden Prozessen, den diversen kleinen technischen Details der Implementation des Algorithmus. Geugeltes Wort: "It depends on your system, your hardware, and the phase of the moon.\ Informatik II { Sommersemester 1999 143 Informatik II { Sommersemester 1999 144 Erinnerung: Erinnerung (Vorlesungsthema 5): sung schon mehrfach verglichen. "The phase of the moon\ etc. wurde dabei aber nicht thematisiert. Mengen A und B : Jedes Element von A mit jedem Element von B vergleichen. Wenn es eine Ordnung "\ auf den Elementen von A und B gibt: Ein gemeinsamer Durchlauf durch beide Mengen in "\{Reihenfolge reicht aus. Die Ezienz von Algorithmen wurde in der Vorle- Fragen: 1. Welche Aspekte wurden statt dessen thematisiert? 2. Inwieweit war die Betrachtung dieser Aspekte eigentlich gerechtfertigt??? Konkretes Beispiel: Wie wurden noch 'mal die bei- den Algorithmen zur Schnittmengenberechnung verglichen? Informatik II { Sommersemester 1999 145 Schlufolgerung seinerzeit in Vorlesung war: 2. Algorithmus ist klar besser. Fragen: War diese Schlufolgerung gerechtfertigt? Wenn ja: inwieweit eigentlich? Und was sind die Gesetzmaigkeiten hinter dieser Allgemeiner Algorithmus fur den Schnitt zweier Ai i A 2 3 5 B 2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 7 11 13 17 19 23 29 31 37 41 43 47 53 j Bj Konsequenz: Bei "unscharfem Hinsehen\ ist die An- zahl der Operationen beim ersten Algorithmus proportional zu jAj jB j und beim zweiten proportional zu jAj + jB j. Informatik II { Sommersemester 1999 146 Beobachtung: Wenn jAj oder jB j sehr klein ist, gilt jAj jB j jAj + jB j. Aber wenn sowohl jAj als auch jB j eine gewisse Grenze uberschritten haben, geht es rapide und ohne ein Halten aufwarts mit jAj jB j jAj + jB j doch eher intuitiven Schlufolgerung? Mathematisch ausgedruckt: Wenn jAj und jB j ins Konkretere Fragen: Unendliche wachsen, wachst auch Worin besteht der Unterschied zwischen jAj jB j und jAj + jB j? Und wie wirkt er sich praktisch aus? jAj jB j jAj + jB j ins Unendliche, also lim jAj jB j = 1 jAj; jBj;!1 jAj + jB j Informatik II { Sommersemester 1999 147 Informatik II { Sommersemester 1999 148 Also: Anscheinend haben wir intuitiv den Fall, da jAj und jB j nicht extrem klein sind, als Mastab genommen. Rechtfertigung: Bei kleinem jAj oder jB j ist die Ezienz Anderes Beispiel: Sortieren von n Elementen Erinnerung: Der einfache Algorithmus "Selection{ Sort\ vertauscht im i{ten Durchlauf der Hauptschleife das Element A[i-1] mit dem kleinsten Element aus A[i-1], A[i], A[i+1]...A[n-1]. nicht so kritisch. Der Unterschied zwischen jAj jB j und jAj + jB j ist bei kleinen Werten jAj oder jB j nicht so dramatisch wie bei groen. Konsequenz: Die Laufzeit fur den i{ten Durchlauf ist ungefahr proportional zu n ; i + 1. Die Laufzeit des gesamten Algorithmus ist also un- Konsequenzen: In erster Linie wird von jetzt an das Verhalten von gefahr proportional zu n X n X i=1 i=1 Algorithmen fur groe Eingaben als Vergleichsmastab genommen. Aber die kritische Frage, ob das jetzt in einem konkreten Fall wirklich der adaquate Mastab ist, bleibt im Hinterkopf. ;! Groenordnung n2. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 149 Zum Vergleich: Mergesort 17 21 41 67 41 12 15 41 67 17 21 41 67 12 41 12 15 23 41 12 15 17 21 23 41 41 67 4 23 88 15 23 150 zen zweier sortierter Teilsequenzen aus Thema 5 ist die Laufzeit fur die Verschmelzung zweier Teilsequenzen mit k und ` Elementen ungefahr proportional zu k + `. 9 9 88 27 44 18 27 44 9 27 44 88 11 11 18 4 36 4 36 ;! Der Aufwand "pro Schicht\ ist proportio- nal zur Zahl n der insgesamt zu sortierenden Elemente, da paarweise disjunkte Teilsequenzen in jeder Schicht behandelt werden. ;! Der Gesamtaufwand ist proportional zu 4 11 18 36 n mal der Anzahl Schichten. 4 9 11 18 27 36 44 88 Also Frage: Wieviele Schichten braucht Mergesort, um n Elemente zu sortieren? 9 11 12 15 17 18 21 23 27 36 41 41 44 67 88 Informatik II { Sommersemester 1999 i = n(n2+ 1) 21 n2 Beobachtung: Mit dem Algorithmus zum Verschmel- 21 17 41 67 41 12 15 23 88 9 27 44 18 11 4 36 21 17 (n ; i + 1) = 151 Informatik II { Sommersemester 1999 152 Beobachtung: Zur besseren U bersicht betrachtet man besser nur die Zweierpotenzen. Resultat: Die Anzahl Schichten verhalt sich ungefahr zu n wie k zu 2k . n Anzahl Schichten Exponent 1 2 1 2 4 2 8 3 3 4 16 4 32 5 5 6 64 6 128 7 7 8 256 8 9 512 9 10 1024 10 Umgekehrt formuliert: Die Anzahl Schichten ist ungefahr gleich log2(n). ;! Groenordnung der Gesamtlaufzeit ist n log2(n). Anschlufrage: Was bedeutet n log2(n) im Verhaltnis zu n2 real? ;! Deutliches Ergebnis. Informatik II { Sommersemester 1999 153 Umkehrtabelle gibt klare Antwort: 154 Frage: Kann man den Fall kleiner Groenordnungen nicht vollig ignorieren? n log2(n) 1 2 5 10 20 50 100 500 1:000 10:000 100:000 1:000:000 1:000:000:000 1:000:000:000:000 Informatik II { Sommersemester 1999 0 1 2 3 4 5 7 9 10 13 17 20 30 40 Antwort: Es gibt auch realistische Szenarien, in denen es um sehr kleine Groenordnungen geht, die Laufzeit des Algorithmus aber trotzdem nicht vernachlassigt werden kann. Konkret: Ein komplexer Algorithmus A hat als Teilprobleme eine groe Zahl kleiner Sequenzen zu sortieren. ;! Entscheidend fur die Laufzeit von A ist, wie ezient der gewahlte Sortieralgorithmus bei kleinen Eingaben ist. ;! n2 verhalt sich groenordnungsmaig zu n log2 n wie Eeeewigkeit zu (beinahe) Echtzeit. Informatik II { Sommersemester 1999 155 Informatik II { Sommersemester 1999 156 Realistisches Szenario: Fur jede x{Koordinate (Kilometer) sortiere alle Orte auf dieser vertikalen Linie untereinander nach ihren y{Koordinaten. Merke: Bei groen Eingaben konnen die Unterschiede in der Laufzeit zweier Algorithmen fur dieselbe Problemstellung dramatisch werden. Es kommt sogar haug vor, da der Unterschied "ins Unendliche\ wachst. Es ist daher zweckmaig, die Laufzeit eines Algorithmus in erster Linie mittels sehr groer Eingaben zu bewerten. Allerdings gibt es auch Szenarien, in denen dieses Kriterium nicht adaquat ist, weil eine sehr groe Zahl kleiner Eingaben zu bearbeiten ist. Informatik II { Sommersemester 1999 157 Informatik II { Sommersemester 1999 158 Thema 8: O{Notation Ziel: Mathematischen Formalismus fur die Asymptotik Problem: Bei exakt gleichen Werten dieser Kenn- der Laufzeit von Algorithmen entwickeln. groen kann die Laufzeit eines Algorithmus immer noch stark variieren. Das heit: Beispiel: Analysieren, was passiert, wenn die Eingaben sehr gro werden. Groe der Eingabe gemessen in einer oder wenigen Kenngroen. Beispiele fur Kenngroen aus Thema 5 der Vorlesung: T{Wert t. A eines Datentyps T, zusatzlicher Gesucht: Information, ob t momentan in A gespeichert ist. Algorithmus: public boolean searchItemInArray ( T[] A, T t ) { for ( int i = 0; i < A.length; i++ ) if ( A[i] == t ) return true; return false; } Sortieren: Anzahl der zu sortierenden Elemente. ;! 1 Kenngroe. Schnittmenge: Groe der beiden zu schneidenden Mengen. ;! 2 unabhangige Kenngroen. Informatik II { Sommersemester 1999 Eingabe: Array 159 Informatik II { Sommersemester 1999 160 Naheliegende Kenngroe: A.length. Beobachtung: Terminologie: Worst Case: Fur jede Kombination von Werten fur zu A.length. Im besten Fall ist das allererste Element schon das gesuchte. ;! Die Laufzeit ist dann im Prinzip unabhangig von A.length. die Kenngroen die maximale Laufzeit, die der Algorithmus fur eine Eingabe mit diesen Kenngroenwerten haben kann. Best Case: Minimale Laufzeit analog zum Worst Case. Average case: Fur jede Kombination von Werten fur die Kenngroen die durchschnittliche Laufzeit "typischer\ Eingaben mit diesen Kenngroenwerten. Konsequenzen: Konsequenz: fur die Laufzeit in Abhangigkeit von den Kenngroen suchen. Auch relevant: Die durchschnittliche Laufzeit des Algorithmus fur "typische\ Eingaben (was immer das heien mag...). groen. Average Case hingegen hangt noch zusatzlich davon ab, was "typisch\ heien soll. Im schlechtesten Fall wird A einmal durchlaufen. ;! Die Laufzeit ist ungefahr proportional Nach oberen und unteren asymptotischen Schranken Worst und Best Case sind Funktionen der Kenn- Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 161 162 Frage: Formalisierung: portional\ zu irgendwas charakterisiert. Was soll denn das genau heien? Es gibt zwei Konstanten c1 > 0 und c2 > 0, so da fur alle Werte von n1; : : : ; nk gilt: f1(n1; : : : ; nk) c1 f2(n1; : : : ; nk) und f2(n1; : : : ; nk) c2 f1(n1; : : : ; nk). Bisher wurden Laufzeiten immer als "ungefahr pro- Abstrakte Idee: Seien n1; : : : ; nk 2 N die Kenngroen fur eine algorithmische Problemstellung. Seien f1; f2 : N k ;! N zwei Funktionen in den k Kenngroen. Dann sollen f1 und f2 als "ungefahr proportional\ angesehen werden, wenn sie nur in einer gewissen (multiplikativen) Bandbreite voneinander abweichen. Informatik II { Sommersemester 1999 163 c2 . f1 f1 f2 1 . f c1 1 Informatik II { Sommersemester 1999 164 Terminologie: Wenn f1 und f2 nach dieser Formalisierung "ungefahr proportional\ sind, heien sie asymptotisch aquivalent. Notation: f1 f2. Die konstante Funktion mit Wert c wird ebenfalls mit c bezeichnet. Modellannahmen: Die Laufzeit jedes Codestucks, in dem keine Schleife und kein Methodenaufruf vorkommen, ist 1. Die Laufzeit einer Schleife setzt sich additiv zusammen aus { Laufzeit fur die Auswertung der Fortsetzungsbedingung, { Laufzeit fur den Rumpf der Schleife und { Laufzeit fur die interne, unsichtbare Organisation der Schleife selbst. { Speziell bei for{Schleife: Zusatzlich Aufwand fur den Intialisierungsteil und die Fortschaltung. Beobachtung: f ist beschrankt und uberall strikt positiv () f 1. f for ( int i = 0; i < n; i++ ) Initialisierung Informatik II { Sommersemester 1999 165 Informatik II { Sommersemester 1999 Fortschaltung 166 Diskussion: Fortsetzung Modellannahmen: Die Gesamtlaufzeit fur die interne Organisation ei- Diese Modellannahmen sind sicher eine Vereinfa- ner Schleife ist asymptotisch aquivalent zur Anzahl Durchlaufe. Die Laufzeit eines Methodenaufrufs setzt sich addi- tiv zusammen aus { Laufzeit fur den Inhalt der Methode und { Laufzeit fur die interne, unsichtbare Organisation des Methodenaufrufs selbst. Die Laufzeit fur die interne Organisation eines Methodenaufrufs ist 1. Informatik II { Sommersemester 1999 Fortsetzungsbedingung 167 chung der Realitat, aber immer noch ausreichend nahe an der Realitat dran fur aussagekraftige Analysen. Wenn die Laufzeiten zweier Algorithmen nicht asymptotisch aquivalent sind, kann man sofort entscheiden, welcher der beiden besser ist im Falle, da die Kenngroen "ins Unendliche wachsen\. Nur bei asymptotischer A quivalenz mu man noch genauere Vergleiche anstellen. Erinnerung: Wenn Algorithmus A "im Unendlichen\ besser ist als Algorithmus B , kann B bei kleinen Werten der Kenngroen dennoch besser als A sein. Beachte: Bei komplizierteren Algorithmen kann es sein, da die Kenngroen schon recht gro werden mussen, bevor sich der asymptotische Vorteil von A auszuwirken beginnt. Informatik II { Sommersemester 1999 168 Ziel: Wir wurden "\ gerne so denieren, da f1 f2 immer noch gilt, wenn f1 und f2 Technische Unschonheit: c2 . f1 endlich viele Nullstellen haben, ansonsten aber die Bedingung fur asymptotische f1 A quivalenz erfullen. f2 1 . f c1 1 Losung: f1 f2 soll von jetzt an schon gelten, wenn nur f1(n1; : : : ; nk) c1 f2(n1; : : : ; nk) und f2(n1; : : : ; nk) c2 f1(n1; : : : ; nk) fur n1 N1; : : : ; nk Nk mit beliebigen, aber festen Werten N1; : : : ; Nk 2 N gelten. Erlauterung: Durch die Nullstellen von f2 gilt nicht mehr f1 f2 (kein c1 > 0 moglich). Aber "ins Unendliche\ gilt f1 f2 irgendwie doch. Informatik II { Sommersemester 1999 169 Informatik II { Sommersemester 1999 170 Entscheidend fur guten Durchblick: Fundamentale Einsicht dazu: Das heit hier: Seien n; k 2 N fest. Seien f1; f2; : : : ; fn beliebige Funktionen N k ;! N . Seien F1(x) := maxff1(x); f2(x); : : : ; fn(x)g und F2(x) := f1(x) + f2(x) + + fn(x) fur x 2 N k . Reduktion auf das Wesentliche. Die Gesamtlaufzeit eines Algorithmus setzt sich additiv aus den Laufzeiten der einzelnen Teile zusammen. Nur die asymptotisch am schnellsten wachsenden Teile zahlen. Informatik II { Sommersemester 1999 Dann gilt F1 F2 mit c1 = 1 und c2 = n. Denn: Fur x 2 N k gilt maxff1(x); f2(x); : : : ; fn(x)g 1 (f1(x) + f2(x) + + fn(x)) und f1(x) + f2(x) + + fn(x) n maxff1(x); f2(x); : : : ; fn(x)g. 171 Informatik II { Sommersemester 1999 172 Denition: Seien f1 und f2 Funktionen Nk Erinnerung von zwei Folien fruher: f1 + + fn maxff1; : : : ; fng. Konsequenz: Seien f1; : : : ; fn Funktionen N k ;! N , so da f2; : : : ; fn 2 O(f1). ;! Dann gilt (f1 + + fn) f1. ;! N , so da es ein c1 > 0 und N1 2 N mit f1(n) c1 f2(n) fur n N1 gibt, aber kein c2 > 0 und N2 2 N mit f2(n) c2 f1(n) fur n N2. Dann heit f1 durch f2 dominiert. Beachte: Diese Konsequenz ist die formale Konkreti- Notation: Fur eine Funktion f : N k ;! N ist (f ) die Menge aller zu f asymptotisch aquivalen- Beweis dieser Konsequenz: ten Funktionen, o(f ) die Menge aller von f dominierten Funktionen und O(f ) = (f ) [ o(f ). sierung von "nur die am schnellsten wachsenden Teile zahlen\. Nachste zwei Folien. Annahme rein zur notationellen Vereinfachung in der Formulierung des Beweises: f1(x) 6= 0 fur alle x 2 N k . ;! Allgemein ublicher Terminus "O{Notation\. Informatik II { Sommersemester 1999 173 Zu zeigen: Es gibt c1; c2 > 0, so da fur alle x 2 N k gilt: 174 Bleibt noch zu zeigen: c2 < +1. Begrundung fur c2 < +1: f1(x) c1 (f1(x) + + fn(x)) und (f1(x) + + fn(x)) c2 f1(x). Erinnerung: Voraussetzung war f2; : : : ; fn 2 O(f1). Mit anderen Worten: Es gibt d2; : : : ; dn > 0 mit fi(x) < di f1(x) fur x 2 N k und i 2 f2; : : : ; ng. Konstruktion von c1 und c2: c1 := 1 tut's oensichtlich. Nun c2: c2 f1(x) (f1(x) + + fn(x)) () c2 1 + ff2((xx)) + + ffn((xx)) 1 1 Also: Setze Informatik II { Sommersemester 1999 ;! Fur alle x 2 N k gilt f2(x) + + fn(x) d + + d < +1 2 n f1(x) f1(x) Insbesondere schluendlich: Informatik II { Sommersemester 1999 c2 = maxk 1 + ff2((xx)) + + ffn((xx)) < +1 x2N 1 1 c2 := maxk 1 + ff2((xx)) + + ffn((xx)) > 0 x2N 1 1 175 Informatik II { Sommersemester 1999 176 Gesamtlaufzeit gema Modellannahmen = 1{mal beschrankte Laufzeit fur "int sum=0\ + 1{mal beschrankte Laufzeit fur den Initialisierungs- Einfaches, kunstliches Beispiel: int sum = 0; for ( int i = 0; i < m; i++ ) { int k = i * i; for ( int j = 0; j < n; j++ ) sum += k * j; } + + + + + + + Informatik II { Sommersemester 1999 177 Zusammenfassung: Die Gesamtlaufzeit jedes dieser neun Summanden ist teil der aueren Schleife m{mal beschrankte Laufzeit fur Fortsetzungsbedingung und Fortschaltung in der aueren Schleife 1{mal Laufzeit fur die interne Organisation der aueren Schleife ( m) m{mal beschrankte Laufzeit fur "int k=i*i\ m{mal beschrankte Laufzeit fur den Initialisierungsteil der inneren Schleife m n{mal beschrankte Laufzeit fur Fortsetzungsbedingung und Fortschaltung in der inneren Schleife m{mal Laufzeit fur die Organisation der inneren Schleife (jeweils n) (m n){mal beschrankte Laufzeit fur "sum+=k*j\. Informatik II { Sommersemester 1999 178 A hnliches Beispiel: Selection{Sort Erinnerung: int indexOfMin (Object[] A, int first_index, Comparator cmp) { int index = first_index; for ( int i=first_index+1; i<A.length; i++ ) if ( cmp.is_less_than ( A[i], A[index] ) ) index = i; return index; } 1 oder m oder m n. void swapComponents (Object[] A, int index1, int index2) { Object x = A[index1]; A[index1] = A[index2]; A[index2] = x; } "Nur die am schnellsten wachsenden Teil zahlen\ ;! Gesamtlaufzeit des Beispiels ist m n. void sort (Object[] A, Comparator cmp) { for ( int i=0; i<A.length; i++ ) { int index = indexOfMin (A, i, cmp); swapComponents (A[i], A[index]); } } Informatik II { Sommersemester 1999 179 Informatik II { Sommersemester 1999 180 Komplexeres Beispiel: Mergesort mit beliebiger Eingabelange (vgl. Vorlesungsthema 5) "Erbsenzahlen\ fur Selection{Sort: Sei n := A.length. Laufzeit fur die Abarbeitung von indexOfMin ist n ; i + 1 im i{ten Durchlauf durch die Schleife in sort. Laufzeit fur eine Abarbeitung von swapComponents ist immer 1. ;! Laufzeit fur den i{ten Durchlauf durch die Schleife in sort ist n ; i + 1. ;! Gesamtlaufzeit ist n X i=1 (n ; i + 1) = n X i=1 21 17 41 67 41 12 15 23 88 9 27 21 17 17 21 41 67 41 12 15 41 67 12 41 17 21 41 67 i = n(n2+ 1) n2 23 88 15 23 12 15 23 41 12 15 17 21 23 41 41 67 9 9 88 27 27 9 27 88 9 27 88 9 12 15 17 21 23 27 41 41 67 88 Informatik II { Sommersemester 1999 181 Iterative Implementation: 182 Laufzeit des Algorithmus Vorbetrachtung: Anzahl der Durchlaufe durch die auere Schleife bestimmen. public void sort ( Object[] A, Comparator cmp ) { for ( int k = 1; k < n; k *= 2 ) for ( int j = 0; j < n+k; j += 2*k ) { int first = j; int middle = j + k - 1; int last = j + 2*k - 1; if ( n < last ) last = n; merge ( A, cmp, first, middle, last ); } } Erinnerung: Ist die Anzahl der Elemente eine Zweierpotenz 2k , dann werden zum Sortieren k Schleifendurchlaufe benotigt. Anders herum formuliert: k = log2 n Schleifendurchlaufe fur n = 2k Elemente. Erinnerung aus Thema 6 der Vorlesung: Aufruf merge(A,cmp,first,middle,last) erwartet, da A[first]..A[middle] und A[middle+1]..A[last] in sich sortiert sind, und sorgt dafur, da A[first]..A[last] in sich sortiert ist. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 183 Beobachtung: Fur beliebiges n sei N = 2k die kleinste Zweierpotenz n. ;! Die Anzahl der Schleifendurchlaufe fur n Elemente ist k = log2 N = dlog2 ne. Fehlt noch: Laufzeit pro Durchlauf durch die auere Schleife. Informatik II { Sommersemester 1999 184 Laufzeit pro Durchlauf der aueren Schleife: Erinnerung: Zum Zusammenfugen zweier in sich sortierter Teilse- public void sort ( Object[] A, Comparator cmp ) { for ( int k = 1; k < n; k *= 2 ) for ( int j = 0; j < n+k; j += 2*k ) { int first = j; int middle = j + k - 1; int last = j + 2*k - 1; if ( n < last ) last = n; merge ( A, cmp, first, middle, last ); } } quenzen zu einer neuen werden beide Teilsequenzen insgesamt einmal durchlaufen. j1 17 21 41 67 In einem Schleifendurchlauf werden paarweise disjunkte Teilsequenzen durchlaufen. 185 ;! Gesamtlaufzeit fur alle Aufrufe von in einem Durchlauf der aueren Schleife ist ebenfalls n. merge ;! Gesamtlaufzeit des Algorithmus ist n dlog2 ne. Informatik II { Sommersemester 1999 186 Rechnen mit der O{Notation Merke: Erinnerung: Fur feste n; k 2 N deniert die Asymptotik eine partielle Ordnung auf den Funktionen N k ;! N . Damit konnen die Laufzeiten zweier Algorithmen miteinander verglichen oder die Laufzeit eines Algorithmus durch eine Funktion ausgedruckt werden. Bei asymptotischen Betrachtungen von Funktionen mussen nur die "am schnellsten wachsenden\ Summanden betrachtet werden. Falls c1; c2 > 0 und n0 2 N existieren mit f1(n) c1f2(n) und f2(n) c2f1(n) fur n n0, schreiben wir f1 2 (f2) (und umgekehrt: f2 2 (f1)). Falls nur c1, aber nicht c2 existiert: f1 2 o(f2). O(f2) = (f2) [ o(f2) ;! f1 2 O(f2) bedeutet gerade, da es ein c1 mit f1 c1 f2 gibt (egal ob es umgekehrt ein c2 gibt oder nicht). Auch bei komplizierten Algorithmen kommt Sinngema alles ubertragbar auf den Fall mehrerer man daher im allgemeinen zu vergleichsweise einfach strukturierten Funktionen. Informatik II { Sommersemester 1999 i 12 15 17 21 Konsequenz: Aufruf von merge ist asymptotisch aquivalent zur Lange des Endergebnisses. Laufzeit pro Durchlauf auerhalb merge: oensichtlich n. Frage: Was ist mit merge selbst? Informatik II { Sommersemester 1999 j2 12 15 23 41 Kenngroen. 187 Informatik II { Sommersemester 1999 188 Weitere Beobachtung: Wenn es fur f : N ;! R ein n0 2 N mit f (n) 1 fur n n0 gibt, dann gilt bf c df e. Beobachtung: Erinnerung Logarithmengesetz: Fur a; b > 1 gilt loga n = log b a logb n Seien fa; fb : N n f0g ;! N mit { fa(n) = dloga ne und { fb(n) = dlogb ne. Begrundung: Nur die Existenz von c > 0 und N0 2 N zu zeigen, so da df (n)e c bf (n)c fur n N0 gilt. Losung: c := 2. Insbesondere: blog nc dlog ne. Also: Es gilt fa dloga be fb und fb dlogb ae fa. ;! fa fb. ;! Basis a > 1 des Logarithmus braucht bei Somit Rechtfertigung fur weitere Vereinfachung der Schreibweise: (log n) statt (dlog ne), O(log n) statt O(dlog ne), etc. asymptotischen Betrachtungen nicht angegeben zu werden: dloga ne ;! dlog ne. Informatik II { Sommersemester 1999 189 Oensichtliche Transitivitaten: 190 Generelle Limes{Regel (ohne Beweis): Wenn f2 : N ;! N nur endlich viele Nullstellen hat, dann gilt Wenn f1 2 O(f2) und f2 2 O(f3), dann auch f1 2 O(f3). Wenn f1 2 o(f2) und f2 2 o(f3), dann auch f1 2 o(f3). f1 2 o(f2) () n;!1 lim ff1((nn)) = 0 2 Nutzlich in diesem Zusammenhang: Regel von l'H^opital Wenn f1 2 O(f2) und f2 2 o(f3) oder f1 2 o(f2) und f2 2 O(f3), dann auch f1 2 o(f3). Salopp formuliert: f (x) = lim f 0(x) lim x;!1 g0(x) x;!1 g(x) Wenn f1 2 (f2) und f2 2 (f3), dann auch f1 2 (f3). 00 000 = x;!1 lim fg00((xx)) = x;!1 lim fg000((xx)) = Wenn f1 2 O(f2) und f2 2 (f3) oder f1 2 (f2) und f2 2 O(f3), dann auch f1 2 O(f3). Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 191 Informatik II { Sommersemester 1999 192 Vergleich von Potenzfunktionen: Seien k; ` 2 N mit k < `. k lim n`1;k = 0 ;! n;!1 lim nn` = n;!1 Beispielanwendung der Regel von l'H^opital: lim 1=x lim logxe x = x;!1 1 =0 x;!1 ;! dlog ne 2 o(n) ;! n dlog ne 2 o(n2) Konsequenz aus der generellen Limes{Regel: nk 2 o(n`) ;! Mergesort ist tatsachlich um Groenord- Anwendung auf Schnittmengenalgorithmus (Vorlesungsthema 5): Der "schnelle\ Algorithmus hat im Worst und Best Case Laufzeit (jAj + jB j). Worst Case fur den "naiven\ Algorithmus: tritt auf im Falle A B . ;! Im Fall jAj jB j ist der Unterschied wieder um Groenordnungen: (jAj) ! (jAj2) nungen schneller als Selection{Sort. Informatik II { Sommersemester 1999 193 194 Exkurs: Exponentielle Laufzeit Bedeutet: Es gibt ein a > 1, so da die Laufzeit an ist. Beispiel: Fur a 2 N ; a > 1 ist das die Mindestlaufzeit des "primitiven\ Algorithmus fur jedes Problem aus n sukzessiven Entscheidungen mit a Alternativen. Das heit: { Das Problem besteht darin, n Entscheidungen zu treen. { Fur jede Entscheidung stehen a Alternativen zur Auswahl. { "Primitiver\ Algorithmus: Alle an Kombinationen von Entscheidungen werden durchlaufen, um die beste zu nden. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 195 Fur viele konkrete Entscheidungsprobleme nach die- sem Muster gibt es bessere als exponentielle Algorithmen. Es gibt aber auch Entscheidungsprobleme, fur die kein Algorithmus bekannt ist, der im Worst Case weniger als exponentielle Laufzeit hat. Fur eine ganze Klasse solcher Probleme (NP { schwere Probleme) legen Ergebnisse aus der Vorlesung Theoretische Informatik nahe, da die Laufzeit im Worst Case grundsatzlich mindestens exponentiell ist. Beispiel: { Gegeben ein Lieferwagen und n Stucke zum Transportieren, wie kann moglichst viel mit einer Fuhre mitkommen. { Entscheidungen: Fur jedes Stuck, ob es mitkommt oder nicht (also a = 2). Informatik II { Sommersemester 1999 196 Vergleich zweier Exponentialfunktionen wieder mit der generellen Limes{Regel: Sei 1 < a < b. Merke: O(), o() und () sind transitiv. o() "schlagt\ dabei O(), und O() "schlagt\ (). x x lim ab = 0 ;! x;!1 lim abx = x;!1 ;! ax 2 o(bx) Alle Logarithmusfunktionen sind asympto- Vergleich Potenz-/Exponentialfunktion mit der Regel von l'H^opital: k ;1 k k ;2 lim x = lim k x = lim k (k ; 1) x x;!1 ax x;!1 log a ax x;!1 (log a)2 ax e e = = x;!1 lim (log ak)! k ax = 0 e tisch zueinander aquivalent. Jede Potenzfunktion wachst schneller als jede Logarithmusfunktion. Jede Exponentialfunktion wachst schneller als jede Potenzfunktion. Potenzfunktionen (bzw. Exponentialfunktionen) sind untereinander grundsatzlich nicht asymptotisch aquivalent. ;! nk 2 o(an) Informatik II { Sommersemester 1999 197 Konkrete Zahlen: n n2 n3 n4 2n 3n 3 1 1 1 1 2 2 4 8 16 4 9 3 9 27 81 8 27 4 16 64 256 16 81 5 25 125 625 32 243 ... ... ... ... ... ... 10 100 1.000 10.000 1.024 59.049 ... ... ... ... ... ... 20 400 8.000 160.000 ... ... 100 10.000 ... 10 6 ... 8 10 6 10 ... 30 10 3,510 Informatik II { Sommersemester 1999 198 Fakultatsfunktion n! = 1 2 3 (n ; 1) n Beobachtung: Die Anzahl von Permutationen einer n{elementigen Menge ist n!. ;! Sortieren durch systematisches Auspro- bieren aller Permutationen, bis eine Permutation in Sortierreihenfolge gefunden ist, wurde Laufzeit proportional n! oder noch schlechter erfordern. 9 ... 47 510 Beachte auch: Verbesserung der Computerpower um z.B Faktor 10 erlaubt p bei nk um Faktor k 10 groere Eingaben in dersel- Frage: Wie schlecht ist Laufzeit (n!)? ben Zeit zu losen, aber bei an konnen die Eingaben nur um den Summanden loga(10) groer werden: am = 10 an () m ; n = loga(10) Informatik II { Sommersemester 1999 199 Informatik II { Sommersemester 1999 200 A hnliches Beispiel: Traveling{Salesperson Problem (TSP) Gegeben: n Punkte in der Ebene. Gesucht: Kurzeste geschlossene Rundtour startend (und endend) mit p1. p10 p5 p4 p1 p14 p16 p9 p11 p2 p7 p3 p6 zeigen, denn: Fur " > 0 mit " < a ; 1 wurde dann ebenfalls n! 2 O((a ; ")n) gelten. Wegen (a ; ")n 2 o(an) und Transitivitat wurde somit n! 2 o(an) gelten. Beweisidee zu an 2 O(n!): p8 Beliebig, aber fest gegeben: a > 1. Gesucht: na 2 N und ca > 0, so da n! ca an fur n na ist. p13 p15 p12 Vermutung: n! wachst so schnell, da sogar an 2 o(n!) fur alle a > 1 gilt. Beobachtung: Es reicht an 2 O(n!) fur alle a > 1 zu Anzahl Rundtouren: (n ; 1)! Frage: Wie schlecht ist systematisches Beweis: Nachste zwei Folien. Ausprobieren hier also mindestens? Informatik II { Sommersemester 1999 201 Ansatz: Logarithmisierung und Anwendung der Logarithmengesetze n! ca an () log2 () n X i=1 n ! Y i=1 i log2 (ca an) () ; log2 (ca) n log2(a) ; () log2 c1 a n X i=1 i=1 i=1 1 log2 c da () c1 2da a a () ca 21da log2(i) Konsequenz: Mit na := dae und ca := gewunscht n! ca an fur alle n na. (log2(a) ; log2(i)) Fur n dae ist der rechte Ausdruck dae X 202 Wichtig: da ist eine Konstante und damit insbesondere unabhangig von n. Auswertung: log2(i) log2(ca) + n log2(a) n X Informatik II { Sommersemester 1999 1 2da gilt wie ;! Beweis fertig. (log2(a) ; log2(i)) =: da Informatik II { Sommersemester 1999 203 Informatik II { Sommersemester 1999 204 Fibonacci{Reihe Genauere Asymptotik von fib: Durch Anwendung der "Schullosung\ fur quadratische Gleichungen r Einkreisung: "fib\ wachst ... ... hochstens so schnell wie 2n: Falls fib(k) c 2k fur alle k auch < n ist, dann gilt fib(n) = fib(n ; 1) + fib(n ; 2) c (2n;1 + 2n;2) = c 2n;2 3 c 2n : p ... mindestens so schnell p k wie ( 2)n: Falls fib(k) c ( 2) fur alle k < n ist, dann gilt auch fib(n) = fib(n ; 1) + fib(n ; 2) p p c ( 2)n;1 + ( 2)n;2 p p = c ( 2)n;2 2 + 1 p p c ( 2)n;2 2 = c ( 2)n : Informatik II { Sommersemester 1999 Idee: Gesucht ist a > 1 mit an = an;1 + an;2 () a2 = a + 1 () a2 ; a ; 1 = 0 r () a = 21 14 + 1 Resultat: "fib\ ist asymptotisch aquivalent zu p !n 1+ 5 2 205 (1; 618)n Informatik II { Sommersemester 1999 206 Thema 9: Asymptotik und Kodierungslange Merke: Fallbeispiel: Wie so oft Sortieren Algorithmen mit exponentieller Laufzeit sind im Grunde "jenseits von gut und bose\. Exponentielle Laufzeit wachst sogar so schnell, da multiplikative Verbesserungen der Rechenpower sich nur noch additiv auf die Groe der Eingaben, die in fester Zeit bearbeitet werden konnen, auswirken. Die Fibonacci{Reihe wachst so schnell wie eine Exponentialfunktion mit Basis 1; 618. Die Fakultatsfunktion wachst sogar noch schneller als alle Exponentialfunktionen. Informatik II { Sommersemester 1999 2 x2 + px + q = 0 () x = ; p2 p4 ; q Erinnerung: Bisheriger "Rekord\ ist (n log n). Aber: Dieses Resultat beruhte auf stillschweigenden Voraussetzungen. Konkret: Die Operationen auf dem Datentyp der zu sortierenden Elemente wurden implizit als (1) angenommen. Welche Operationen sind das: { Zuweisung einer Variable zu einer anderen, { Vergleich zweier Variablen. 207 Informatik II { Sommersemester 1999 208 Zuweisung: Kann in Java grundsatzlich als (1) an- genommen werden (nur Referenz kopiert bei Klassentypen). Also zu betrachten: Beispiele: java.lang.BigNumber Zahlen. fur beliebig groe ganze Datentyp String zu sortieren nach Telefonbuchord- Vergleich zweier Elemente nung (lexikographisch). In vielen Anwendungsfallen des Sortierproblems reicht ein groenbeschrankter Datentyp wie int oder double aus, um auch die allergroten auftretenden Zahlen zu kodieren. ;! Annahme (1) Laufzeit pro Vergleich entspricht der empirischen Beobachtung der "Wachstumskurve\. Ansonsten fuhrt die Annahme (1) aber zu einer systematischen Unterschatzung der empirischen "Wachstumskurve\! Lexikographisch zwei Strings S1 und S2 Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 209 Algorithmus fur lexikographischen Zeichen. 210 Lexikographischer Vergleich zweier Strings ist im allgemeinen nicht in O(1) Laufzeit moglich, sondern kann proportional zur Maximallange k0 der public class LexStringComparator implements Comparator { public boolean isLessThan ( Object o1, Object o2 ) { String str1 = (String)o1; String str2 = (String)o2; Strings werden. Konsequenz: (n log n) als Gesamtlaufzeit fur Mergesort ist hier for ( int i = 0; ; i++ ) if ( i == str2.length ) return false; else if ( i == str1.length ) return true; else if ( str1[i] < str2[i] ) return true; else if ( str1[i] > str2[i] ) return false; nicht korrekt, sondern im Worst Case (k0 n log n). Problem: Wenn sich die Strings im wesentlichen nur } } Invariante: Falls der Algorithmus bis zum Ende des i{ten Durchlaufs nicht abgebrochen wur- de, gilt str1.length>=i, str2.length>=i sowie str1[j]==str2[j] f ur alle 0 1 am Informatik II { Sommersemester 1999 Falls S1 ein Prax von S2 ist: S1 < S2. Falls S1 = S2 oder S2 ein Prax von S1 ist: S1 6< S2. Ansonsten entscheidet das erste ungleiche Beobachtung: Stringvergleich: Ende des i{ten Durchlaufs. vergleichen: j 2 f ;:::;i ; g 211 in den letzten Zeichen unterscheiden, mu jeder String mindestens einmal durchlaufen werden. ;! Es geht im Worst Case grundsatzlich nicht asymptotisch schneller als (K ), K Summe aller Stringlangen. Frage: Geht es in (K ) Laufzeit? Informatik II { Sommersemester 1999 212 Antwort: Es geht in (K ) Laufzeit mit Idee fur Umsetzung: einem Algorithmus namens Bucketsort. Ideen: Sei k0 weiterhin die maximale Lange unter den zu sortierenden Strings. Die einzelnen Strings kommen gema ihrer Lange erst nach und nach "ins Spiel\. Schleifeninvarianten: Nach i Durchlaufen sind { alle Strings mit Lange k0 ; i + 1 im Spiel und { untereinander nach den Zeichen mit den Indizes k0 ; i + 1; k0 ; i + 2; ::: lexikographisch sortiert. Konsequenz: Nach k0 Durchlaufen sind alle Strings im Spiel und lexikographisch untereinander sortiert. Informatik II { Sommersemester 1999 213 Beispiel: Ein "Korbchen\ (Bucket) fur jeden Buchstaben des Alphabets. Im Durchlauf Nr. i wird jeder String str, der mindestens k0 ; i + 1 Zeichen hat, in das Bucket fur Zeichen str[k0 ; i + 1] gesteckt. Die Strings mit mehr als k0 ; i + 1 Zeichen werden in der Reihenfolge ihrer bisherigen Sortierung auf die Buckets verteilt. ;! Unter Strings mit gleichem Zeichen am Index k0 ;i+1 wird die Reihenfolge aus den vorhergehenden Runden bewahrt. Die neuen Strings (also die mit genau k0 ; i + 1 Zeichen) werden schon vor den langeren Strings auf die Buckets verteilt. ;! Praxe werden richtig eingeordnet. Informatik II { Sommersemester 1999 214 1. Runde: String Lange Antonio 7 Thomas 6 Andrea 6 Sabine 6 7 Eusebia Anton 5 Gerda 5 Tobias 6 7 Antonia 7 Andreas Ibrahim 7 a Eusebia Antonia b c m n o Ibrahim s Andreas Antonio z Informatik II { Sommersemester 1999 215 Informatik II { Sommersemester 1999 216 2. Runde: a e i s 3. Runde: Andrea a Andreas b Gerda Thomas Eusebia e Andrea h Ibrahim n Anton Tobias Sabine Eusebia Antonia Thomas Ibrahim Andreas Antonio Tobias Sabine Antonia Antonio z z Informatik II { Sommersemester 1999 4. Runde: a 217 Gerda Eusebia i Tobias m n o 5. Runde: Ibrahim d e Informatik II { Sommersemester 1999 Sabine a b c Tobias d Andrea o Thomas Sabine Andreas Thomas Anton Antonia r s Antonio t r 218 Andrea Ibrahim Gerda Eusebia Anton Antonia Antonio Andreas z z Informatik II { Sommersemester 1999 219 Informatik II { Sommersemester 1999 220 6. Runde: 7. Runde: a Sabine b Ibrahim e Gerda h n o u Thomas Andrea Tobias Andreas Anton Antonia a Andrea e Eusebia f g Gerda h i Ibrahim s Sabine t Thomas Andreas Anton Antonia Antonio Antonio Eusebia Tobias z z Informatik II { Sommersemester 1999 221 Implementation von Bucketsort in Java: se java.util.Vector ist im Prinzip ein Array, bei dem Elemente eingefugt und geloscht werden konnen. Jeder Bucket kann als ein Vector{Objekt realisiert werden. Die Buckets bilden also einen Array vom Typ mit 26 Elementen. Arrayindex fur das Zeichen, das in der char{Variable c gespeichert ist: (int)(Character.toLowerCase(c)-'a') Informatik II { Sommersemester 1999 222 Fortsetzung Implementation von Bucketsort in Java Erinnerung: Ein Objekt der vordenierten Klas- Vector[] Informatik II { Sommersemester 1999 Alle Strings werden vor der ersten "Runde\ des Kernalgorithmus durch einen Durchlauf von Bucketsort mit Buckets 1; : : : ; k0 nach Lange sortiert: 1 2 3 4 5 6 7 Anton Thomas Antonio Gerda Andrea Eusebia Sabine Tobias Antonia Andreas Ibrahim Nach jeder "Runde\ des Kernalgorithmus werden die einzelnen Buckets "von 'a' bis 'z'\ in einen separaten Vector A kopiert und von dort in der nachsten Runde wieder verteilt. 223 Informatik II { Sommersemester 1999 224 Asymptotische Laufzeit von Bucketsort: Intuition zur letzten Gleichung: Vorab die n Strings nach ihrer Lange sortieren: 2 O(n + k0 + K ) = O(K ). i = n i= Sei ni die Anzahl der Strings mit mindestens i Zeichen. Aufwand fur Runde Nr. i: 2 (n k ;i ). ;! Gesamtaufwand fur alle Runden: ( 0 +1) 0k 1 0k 1 X X 2 @ n k ;i A = @ niA = (K ) : 0 i=1 0 ( 0 +1) 225 7 5 A n t o n T h o m a i s o A n d r S a b i a e i e n E u s e b A n G e t r o d a n a s A n d r e a o s I a h m b r i i Informatik II { Sommersemester 1999 226 Thema 10: Untere asymptotische Schranken Merke: Erinnerung: Bei der Berechnung der asymptotischen Lauf- Mergesort lost das generische Sortierproblem in (n log n T ) Zeit (T der durchschnittliche Auf- zeit eines generischen Algorithmus (z.B. Sortieralgorithmen wie Mergesort) mu immer mitberucksichtigt werden, da die Basisoperationen auf unterschiedlichen Datentypen unterschiedliche asymptotische Laufzeit haben konnen. Fur den wichtigen Spezialfall des allgemeinen Sortierproblems, da Strings lexikographisch zu sortieren sind, erreicht Bucketsort im Gegensatz zu Mergesort optimale asymptotische Laufzeit im Worst Case (namlich asymptotisch aquivalent zur Gesamtsumme aller Stringlangen). Informatik II { Sommersemester 1999 6 9 T o b i a A n t o n i=1 Informatik II { Sommersemester 1999 1 2 3 4 5 11 11 11 11 11 wand pro Vergleichsoperation). Bucketsort ist mit (K ) asymptotisch optimal fur die lexikographische Sortierung von Strings. Beobachtung: Mit Bucketsort lassen sich z.B. auch ganze Zahlen sortieren: als "Strings\ von Ziern. Interessante Fragen: Ist (n log n T ) allgemein das letzte Wort? Kann man diesen "Rekord\ mit Bucketsort zumin- dest fur gewisse Datentypen und Sortierordnungen unterbieten? 227 Informatik II { Sommersemester 1999 228 Grundsatzliche Grenze: Um n unterschiedliche Werte eines beliebigen Datentyps als Strings mit k verschiedenen Zeichen zu kodieren, werden mindestens blogk nc Zeichen pro String im Durchschnitt benotigt. ;! In Bitdarstellung also mindestens blog2 nc. Idee zum Beweis der grundsatzlichen Grenze: Alle Strings lassen sich zusammen zu einem Digitalbaum mit n Endknoten "%\ verschmelzen. Beispiel aus der Behandlung von Bucketsort: Konsequenzen: aus dieser grundsatzlichen Grenze: Besser als (n log n) kann Bucketsort im Worst Case selbst bei optimaler Kodierung der zu sortierenden Daten nicht werden. Auch kein anderer Algorithmus, weil im Worst Case sicher alle (n log n) Bits mindestens einmal angeschaut werden mussen. Aber immerhin: Mergesort konnte bei lexikographischer Sortierung von Strings nicht einmal besser als (n log2 n) werden. Informatik II { Sommersemester 1999 229 A E G I S n u e b a s r r b o b o e d a i m i n b a h n a a i % i e s s % % t d r e a s % i % % a o a m % % % % T h Informatik II { Sommersemester 1999 o % 230 Beispiel zur hilfreichen Beobachtung (k = 2): Grundsatzliche Grenze folgt nun aus folgender Hilfsbehauptung: Bei einem Baum mit n Endknoten (Blattern) und maximal k Nachfolgern pro Knoten ist die durchschnittliche Hohe aller Endknoten mindestens blogk nc. Hilfreiche Beobachtung: Durch Balancierung des Baumes kann die durchschnittliche Hohe der Endknoten nur besser werden. Informatik II { Sommersemester 1999 231 ! Informatik II { Sommersemester 1999 232 Weiter: in einem optimal balancierten Baum mit m = k` Endknoten hat jeder Endknoten Hohe ` = logk(m). Zusammenfassung: Wegen (log n) oder mehr pro Vergleich ist nichts Besseres als (n log n) beim Sortieren im Worst Case drin. Anschlufrage: Kann unter der idealisierten Annahme, da ein Vergleich zweier Elemente nur (1) Zeit kostet, besser als in (n log n) Laufzeit sortiert werden? ;! In einem optimal balancierten Baum mit m Endknoten, k`;1 < m k`, hat jeder Endknoten Hohe ` ; 1 = blogk (m)c oder ` = dlogk (m)e: Methodisches Problem: Die Anschlufrage bezieht sich nicht auf einen kon- kreten Algorithmus, sondern auf die (unendlich groe!) Menge aller uberhaupt nur denkbaren Sortieralgorithmen. Kann man daruber uberhaupt irgendwelche Aussagen treen? ;! Hilfsbehauptung bewiesen. Informatik II { Sommersemester 1999 233 Konkretisierung der Fragestellung: Erinnerung: Im generischen Sortierproblem (Vorle- sungsthema 2) war nichts uber den Elementtyp bekannt abgesehen von der Vergleichsoperation "\. Dies scheint auch der einzige gemeinsame Nenner aller moglichen Denitionen von Datentyp und "\ zu sein. Ein wahrhaft generischer Sortieralgorithmus hat also keine Information uber die zu sortierenden Elemente abgesehen von der Antwort true/false durch Anwendung von "\ auf Paare von Elementen. Und das auch nur als "Black Box\, d.h. ohne Einsicht in das Wesen von "\ Im Gegensatz etwa zur Ausnutzung des Wesens von lexikographischer Reihenfolge im nichtgenerischen Algorithmus Bucketsort. Konkretisierte Frage: Kann ein Algorithmus, der nur Informatik II { Sommersemester 1999 234 Antwort: Wenn Datentyp T unendlich gro ist, ist im Worst Case nichts Besseres als (n log n) moglich. Beweisidee: Seien a1; : : : ; an 2 T paarweise verschieden mit a1 a2 an. Fur jede Permutation (a(1); : : : ; a(n)) von (a1; : : : ; an) als Eingabe durchlauft der Algorithmus eine charakteristische Folge von Anwendungen von "\. Fur je zwei Permutationen mussen diese Folgen irgendwo auseinanderlaufen. ;! Binare Baumstruktur (Vergleichsbaum). auf paarweisen Vergleichen (also Anwendungen von beruht, mit weniger als (n log n) Vergleichen "\) im Worst Case auskommen? Informatik II { Sommersemester 1999 235 Informatik II { Sommersemester 1999 236 Beispiel: Ausschnitt aus dem Vergleichsbaum fur Mergesort auf vier Elementen. Fortsetzung Beispiel: Durchlauf durch einen einzelnen Zweig des Vergleichsbaums 2 4 1 3 a1 a2 a3 a4 2 4 1 3 a 1 < a2 ? nein ja 2 ja ja nein a1 < a3? ja 1 3 nein 1 2 2 3 4 a1 < a4 ? nein a2 < a3? ja 4 1 3 2< 4 ? nein 1. Stufe links ja a1 < a4 ? nein ja a2 < a4 ? a2 < a4 ? ja 4 a3 < a4 ? a3 < a4 ? 1<3 ? nein 1. Stufe rechts ja Fertig ja nein ja Fertig 2 <1? nein nein Fertig Fertig Fertig Fertig 2<3? ja 2. Stufe 4<3? nein Fertig Informatik II { Sommersemester 1999 237 Ergebnis soweit: Eine binare Baumstruktur mit mindestens so vielen Endknoten "Fertig\, wie es Permutationen von (a1; : : : ; an) gibt. ;! n! Endknoten. Interessierende Groe: Die maximale Anzahl max(n) von Vergleichen auf irgendeinem Pfad von oben nach unten zu einem Endknoten (also die Hohe des Vergleichsbaumes). A quivalente Umformulierung der Behauptung: Es gilt max(n) 62 o(n log n) fur den Vergleichsbaum jedes wahrhaft generischen Sortieralgorithmus. Informatik II { Sommersemester 1999 238 Beweis von max(n) 62 o(n log n): Erinnerung: Es gibt n! Endknoten. Erinnerung: In einem binaren Baum mit m Endkno- ten ist die durchschnittliche Hohe der Endknoten mindestens blog2 mc. ;! max(n) blog2(n!)c Umformung mit Logarithmengesetzen: log2(n!) = log2 bnc X 2 i=2 n ! Y n X i=1 i=1 i =! log2(i) (log2(i) + log2(n ; i + 1)) (Letzter Schritt: zwei oder drei nichtnegative Summanden eliminiert und die verbleibenden Summanden umgruppiert.) Informatik II { Sommersemester 1999 239 Informatik II { Sommersemester 1999 240 Superadditivitat von log im Bereich (2; 1): log2(i) + log2(n ; i + 1) log2(n + 1) Interessantes Nebenresultat: Erinnerung: Im Gegensatz zu Best und Worst Case hangt der Average Case auch noch davon ab, mit welchen Wahrscheinlichkeiten alle moglichen Eingaben auftreten. Sei der Average Case durch die Annahme deniert, i n-i+1 da alle Eingaben der Lange n gleichwahrscheinlich sind (uniforme Zufallsverteilung). n+1 In diesem Fall gibt es keinen generischen Sortieral- gorithmus, dessen Laufzeit auch nur im Average Case 2 o(n log n) ist. Zusammengefat fur genugend groe n: max(n) blog2(n!)c j n k Warum? 2 ; 1 blog2(n + 1)c ! 14 n log2(n) 2 (n log n) Informatik II { Sommersemester 1999 241 Warum auch im Average Case nicht o(n log n): Entscheidend ist in diesem Fall nicht die maximale, sondern die durchschnittliche Anzahl von Vergleichen. Also die durchschnittliche Hohe eines Endknotens im zugehorigen Vergleichsbaum. Schon die war aber im optimalen (namlich balancierten) Fall nicht besser als (n log n). ;! Vgl. Anfang von Thema 10. Informatik II { Sommersemester 1999 243 Informatik II { Sommersemester 1999 242 Merke: Die asymptotische Laufzeit eines generischen Algorithmus hangt von der asymptotischen Laufzeit der Basisoperationen ab, die er "blind\ verwendet. Die Gesamtkodierungslange fur n zu sortierende Elemente eines Datentyps kann im allgemeinen (n log n) im Worst Case werden. Insbesondere kann grundsatzlich kein Sortieralgorithmus im Worst Case asymptotisch schneller als (n log n) sein. Ein wahrhaft generischer Sortieralgorithmus kann beweisbar selbst dann im Worst Case (oder im Average Case unter uniformer Zufallsverteilung) nicht schneller als (n log n) sein, wenn der Aufwand fur einen Vergleich (1) ist. Informatik II { Sommersemester 1999 244 Thema 11: Container Vorgehensweise: Abstrakte Containertypen anhand von Anforderun- Erinnerung: Arrays konnen Sequenzen von Elementen eines be- liebigen Typs speichern. Speziell Array{Typ Object[] kann Objekte jeden Klassentyps speichern (sogar beliebig gemischt in einem einzigen Array{Objekt). Klasse java.util.Vector ist eine Alternative zu Object[], die auch Einf ugen und Loschen von Elementen erlaubt. gen an Zugrismoglichkeiten auf ihre Elemente denieren. Konkrete Datentypen dann in dieses Schema einordnen. ;! Ein konkreter Datentyp kann durchaus unter mehreren abstrakten Typen eingeordnet werden. Wichtigstes Beispiel: Dictionaries (auch assoziative Arrays genannt). Denition: Ein Datentyp, dessen wesentliche Aufgabe die Speicherung von irgendwelchen Elementen ist, ist ein Container. Heute: Containertypen systematisch betrachten und klassizieren. Informatik II { Sommersemester 1999 245 Dictionary: 246 Namensgebende Beispielanwendung: Speichert eine beliebige endliche Sequenz aus Paaren von Objekten. Jedes Paar besteht aus einem Schlussel (key) und einer Information (value). Jeder Schlusselwert darf nur einmal vorkommen. Geforderte Zugrismoglichkeiten: { Einfugen eines neuen Paars. { Loschen eines Paars, das durch seinen Schlussel identiziert wird. { Ausgabe der Information, die zu einem gegebenen Schlussel gespeichert wird. { Durchlauf durch die momentan gespeicherten Elemente. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 247 Die Schlussel sind Worter (Strings). Die Information zu einem Schlussel ist ein erklarender Text: { Zum Beispiel ebenfalls als String{Objekt direkt abgelegt { oder nur der Name eines Files mit dem Text als Inhalt. Allgemein: Jede Art von tabellarischer Information mit eindeutigem Suchschlussel. Beispiel: Daten von Studierenden mit Matrikelnummer als Suchschlussel. Vergleiche: Vorlesungen zu Datenbank- und Informationssystemen. Informatik II { Sommersemester 1999 248 Realisierung in Java: Fortsetzung Erlauterungen Klasse java.util.Dictionary public abstract class Dictionary { public abstract Object put (Object Object public abstract Object remove (Object public abstract Object get (Object Ausnahmesituationen und Ruckgabewerte: key, info); key); key); { Falls key der Schlusselwort eines momentan ge- speicherten Paars ist, wird die Information zu key durch info uberschrieben, und die alte Information ist der Ruckgabewert. { Sonst ist null der Ruckgabewert. { Exception NullPointerException, falls key==null oder info==null. public abstract Enumeration keys (); public abstract Enumeration elements (); ... } Erlauterungen: fugt das Paar (key,info) ein. remove l oscht das Paar mit Schlusselwert key (falls vorhanden). get liefert die Information zum Schlusselwert key. put Informatik II { Sommersemester 1999 249 Object remove ( Object key ) Object get ( Object key ) Liefert jeweils die aktuelle Information zu key (oder null, falls key momentan nicht gespeichert). Informatik II { Sommersemester 1999 250 Muster zum Durchlauf: Fortsetzung Erlauterungen: Fehlt noch: Dictionary dictionary = ...; ... Enumeration elements () Enumeration keys () Exakter Ruckgabetyp: java.util.Enumeration. Aufgabe von Enumeration: Durchlauf durch eine Sequenz von Elementen organisieren. Hier konkret: { keys erlaubt Durchlauf durch alle momentan gespeicherten Schlusselwerte, { elements durch alle zugehorigen Informationen. Beide Arten durchlaufen die einzelnen Paare "im Gleichschritt\, d.h. in exakt gleicher Reihenfolge. Einschrankung: Wahrend eines Durchlaufs darf nicht put oder remove fur das betreende Dictionary{Objekt aufgerufen werden. Informatik II { Sommersemester 1999 Object put ( Object key, Object info ) 251 Enumeration keyEnum = dictionary.keys (); Enumeration infoEnum = dictionary.elements (); while ( keyEnum.hasMoreElements() ) { Object key = keyEnum.nextElement(); Object info = infoEnum.nextElement(); // Mach' irgendwas mit Paar (key,info). } Erlauterung: Mit hasMoreElements wird abgefragt, ob mindestens ein Element noch nicht durchlaufen wurde. Falls ja, liefert nextElement eines davon zuruck. Falls nein, wirft nextElement Exception java.util.NoSuchElementException. Informatik II { Sommersemester 1999 252 Fallbeispiel: Ein sehr primitiver Dictionary{Typ auf Basis von Object[] ist. Falls theKeys!=null ist, gilt { { { public Object put (Object key, Object info) throws NullPointerException { ... } public Object remove (Object key) { ... } public Object get (Object key) { ... } public Enumeration keys () { ... } public Enumeration elements () { ... } ... } theKeys.length>=1, theKeys.length==theInfos.length und theKeys[i]!=null und theInfos[i]!=null fur alle i==0...theKeys.length-1. Fur jedes i bilden theKeys[i] und theInfos[i] ein Paar. Methode ArrayDictionary.get: public Object get (Object key) { if ( theKeys == null ) return null; for ( int i=0; i<theKeys.length; i++ ) if ( theKeys[i] == key ) return theInfos[i]; return null; } 253 Idee fur ArrayDictionary.put: Informatik II { Sommersemester 1999 254 Methode ArrayDictionary.put mit Zusatzmethode Falls theKeys==null ist, werden theKeys und theInfos als Arrays der Gr oe 1 mit Inhalt key bzw. info neu eingerichtet. Falls theKeys!=null und key==theKeys[i] f ur einen Index i gilt, wird theInfos[i] mit info u berschrieben und der vorherige Wert von theInfos[i] zur uckgeliefert. Ansonsten wird theKeys bzw. theInfos durch ein Array mit genau einer Komponente mehr ersetzt, der alle alten Schlussel und Informationen sowie zusatzlich key bzw. info speichert. Informatik II { Sommersemester 1999 Es gilt theKeys==null genau dann, wenn theInfos==null public class ArrayDictionary extends Dictionary { private Object[] theKeys; private Object[] theInfos; Informatik II { Sommersemester 1999 Konsistenzbedingungen: 255 ArrayDictionary.insert: public Object put (Object key, Object info) throws NullPointerException { if ( key == null || info == null ) throw new NullPointerException(); if ( theKeys == null ) { theKeys = new Object[1]; theInfos = new Object[1]; theKeys[0] = key; theInfos[0] = info; return null; } for ( int i=0; i<theKeys.length; i++ ) if ( theKeys[i] == key ) { Object oldInfo = theInfos[i]; theInfos[i] = info; return oldInfo; } insert (key, info); return null; } Informatik II { Sommersemester 1999 256 Zusatzmethode ArrayDictionary.insert: Idee fur ArrayDictionary.remove: Falls key nicht in theKeys auftritt (insbesondere im Fall theKeys==null), wird null zuruckgeliefert, public void insert (Object key, Object info) { Object[] theNewKeys = new Object [theKeys.length+1]; Object[] theNewInfos = new Object [theInfos.length+1]; for ( int i=0; i<theKeys.length; i++ ) { theNewKeys[i] = theKeys[i]; theNewInfos[i] = theInfos[i]; } theKeys = theNewKeys; theInfos = theNewInfos; theKeys[theKeys.length-1] = key; theInfos[theInfos.length-1] = info; } Informatik II { Sommersemester 1999 und es geschieht nichts weiter. Sonst wird theKeys bzw. theInfos jeweils durch einen Array mit genau einer Komponente weniger ersetzt, in dem alle Paare auer (key,info) weiterhin vorkommen. Wenn das letzte Element entfernt wird: theKeys und theInfos werden wieder auf null gesetzt. 257 Methode ArrayDictionary.remove mit Zusatzmethode ArrayDictionary.takeOut: 258 Zusatzmethode ArrayDictionary.takeOut: public void takeOut (int index) { Object[] theNewKeys = new Object[theKeys.length-1]; Object[] theNewInfos = new Object[theKeys.length-1]; for ( int j=0; j<index; j++ ) { theNewKeys[j] = theKeys[j]; theNewInfos[j] = theInfos[j]; } for ( int j=index+1; j<theKeys.length; j++ ) { theNewKeys[j-1] = theKeys[j]; theNewInfos[j-1] = theInfos[j]; } theKeys = theNewKeys; theInfos = theNewInfos; } } public Object remove (Object key) { if ( theKeys == null ) return null; for ( int i=0; i<theKeys.length; i++ ) if ( theKeys[i] == key ) { Object oldInfo = theInfos[i]; if ( theKeys.length == 1 ) { theKeys = null; theInfos = null; } else takeOut (i); return oldInfo; } return null; } Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 259 Informatik II { Sommersemester 1999 260 Zugehorige Enumerationsklasse: Konsistenzbedingung fur ArrayEnumeration: public class ArrayEnumeration implements Enumeration { private Object[] arrayReference; private int currentIndex; Die Elemente von theKeys und theInfos an den Indizes 0 : : :currentIndex sind genau die Elemente, die schon durch ArrayEnumeration.nextElement zuruckgeliefert wurden. public ArrayEnumeration (Object[] arrayReference) { this.arrayReference = arrayReference; currentIndex = -1; } Achtung: public boolean hasMoreElements () { return arrayReference != null && currentIndex < arrayReference.length-1; } Falls zwischendurch Methode put oder remove des zugehorigen ArrayDictionary{Objekts aufgerufen wird, geht alles schief! public Object nextElement () throws NoSuchElementException { if ( arrayReference == null ) throw new NoSuchElementException(); ++currentIndex; if ( currentIndex >= arrayReference.length ) throw new NoSuchElementException(); return arrayReference [currentIndex]; } ;! Begrundung fur die Einschrankung, da das Dic- tionary wahrend einer laufenden Enumeration nicht modiziert werden darf. } Informatik II { Sommersemester 1999 261 Informatik II { Sommersemester 1999 262 Thema 12: Lineare Implementationen von Dictionaries Merke: Container sind Datentypen, deren "Daseins- Obige primitive Implementation eines Dictionaries auf Basis zweier Arrays kostet im Worst Case (n) Laufzeit fur jeden Aufruf von get, put und remove. zweck\ die Speicherung von Objekten ist. In Java gibt es dafur unter anderem Arrays sowie die Klasse java.util.Vector. Dictionaries sind die grundlegende Organisationsform fur Informationssysteme aller Art. Die abstrakte Klasse Dictionary ist der Prototyp fur Dictionaries in Java. Das heit formal: Fur n 2 N sei Tn die Worst{Case{Zeit fur einen Aufruf von get, put oder remove auf einem ArrayDictionary{Objekt mit momentan gespei- cherten Paaren. n Es gibt Konstanten c1; c2 > 0, so da c1 n Tn c2 n fur alle n 2 N gilt. Frage: Geht es besser? Informatik II { Sommersemester 1999 263 Informatik II { Sommersemester 1999 264 Erlauterung: Ein Objekt dieser Klasse garan- Ansatz: Die Arrays sind sortiert nach den Schlusselwerten. Voraussetzung: Irgendeine Sortierreihenfolge ist auf den Schlusselwerten deniert. Realisierung: Wie ublich mit Implementationen von Interface Comparator. cmp.isLessThan(theKeys[i-1],theKeys[i])==true get geht nun in (log n) Zeit im Worst Case mit binarer Suche. Vorteil: Methode public Object get ( Object key ) { if ( theKeys == null ) return null; int first = 0; int afterLast = theKeys.length; while ( afterLast - first > 1 ) { int median = ( afterLast - first ) / 2; if ( cmp.isLessThan(key,theKeys[median]) ) afterLast = median; else first = median; } if ( theKeys[first] == key ) return theInfos[first]; else return null; } Realisierung: public class SortedArrayDictionary extends Dictionary { private Object[] theKeys; private Object[] theInfos; private Comparator cmp; public SortedArrayDictionary ( Comparator cmp ) { this.cmp = cmp; } ... } Informatik II { Sommersemester 1999 tiert als zusatzliche Konsistenzbedingung gegenuber ArrayDictionary, da f ur alle i==1...theKeys.length-1 gilt: 265 Analyse der binaren Suche: Informatik II { Sommersemester 1999 266 Weitere Methoden von SortedArrayDictionary: Schleifeninvariante: Vor und nach jedem Durchlauf (auch dem letzten!) gilt: { afterLast > first. { Wenn key uberhaupt in theKeys gespeichert ist, dann an einem der Indizes first...afterLast-1. Methode put darf das neue Element nicht einfach ans Ende hangen, sondern mu es an der richtigen Position im Array einfugen: Schleifenvariante: Die Dierenz afterLast - first wird in jedem Durchlauf ungefahr\ halbiert (genaues "Erbsenzahlen\ "ausgelassen). Alle anderen Methoden konnen unmittelbar von ArrayDictionary ;! Ungefahr log2 n Durchlaufe im Worst Case. ebenso die Enumerationsklasse ArrayEnumeration. ;! (log n) Laufzeit im Worst Case. Informatik II { Sommersemester 1999 ubernommen werden, 267 Informatik II { Sommersemester 1999 268 Bemerkung: Alternative: Verzeigerungsstrukturen Hier behandelte Variante erreicht auch im Best Case Motivation: SortedArrayDictionary braucht wie ArrayContainer (n) Laufzeit f ur's Einfugen und nichts Besseres als (log n) Laufzeit. Einfache Variation erreicht (1) im Best Case: Prufe einfach nach jeder Berechnung von median, ob median nicht schon das gesuchte Element ist. Ware vorteilhaft, falls die 50%, 25%, 75%{Quantile etc. besonders haug auftreten. ;! Nicht sehr realistisch. Fur eigentlich jede realistische Denition der Haug- keitsverteilung ist der Average Case aber auch mit dieser Modikation nicht besser als (log n). Loschen eines Elements. In Anwendungen, in denen die Schlusselmenge im wesentlichen konstant bleibt und nur andauernd get aufgerufen wird, ist das eigentlich kein Problem. Fur andere Anwendungen mu man aber noch mehr tun. Konkrete technische Hurde: Arrays konnen nicht beliebig wachsen oder schrumpfen. Auch Verwendung von java.util.Vector lost das Problem nicht: Methoden wie addElement haben intern mehr Aufwand als man denkt! Informatik II { Sommersemester 1999 269 Andere Idee: 270 Idee: Je eine verzeigerte Liste fur Schlusselwerte und Informationen. Die einzelnen Schlussel (bzw. Infos) sind nicht mehr Komponenten von Arrays, sondern eigenstandige, "freischwebende\ Objekte und untereinander durch "Querreferenzen\ verzeigert. Konsistenzbedingungen: Beide Listen sind gleich lang. Der Schlusselwert und die Information eines Paares sind in theKeys bzw. theInfos an der gleichen Position gespeichert. Das letzte Listenelement verweist auf null anstelle eines nachsten Elements. Vorbetrachtung: Lineare Verzeigerung. value Hilfsmittel: class Item { public Item public Object } Informatik II { Sommersemester 1999 null theKeys next next; value; value Java{Package! Informatik II { Sommersemester 1999 null theInfos Beachte: Zugri reduziert auf's eigene next 271 Informatik II { Sommersemester 1999 272 In Java: Intuition zu get: Situation nach zwei Durchlaufen durch die Schleife. public class LinearLinkedDictionary { private Item theKeys; private Item theInfos; currentKey public Object get ( Object key ) { Item currentKey = theKeys; Item currentInfo = theInfos; while ( true ) { if ( currentKey == null ) return null; if ( currentKey.value == key ) return currentInfo.value; currentKey = currentKey.next; currentInfo = currentInfo.next; } } null theKeys currentInfo theInfos null ... } Informatik II { Sommersemester 1999 273 Informatik II { Sommersemester 1999 274 Realisierung von LinearLinkedDictionary.put: Ideen fur LinearLinkedDictionary.put: Beide Listen werden wie in get schrittweise simultan durchlaufen. Falls key dabei gefunden: Wie ublich Information uberschreiben und alte Information zuruckliefern. Ansonsten wird ein neues Paar (key,info) vorne an theKeys und theInfos angef ugt. Warum vorne und nicht hinten oder irgendwo mittendrin? Antwort: Technisch einfacher. Dadurch vermiedene Komplikationen: Kommen unmittelbar im Anschlu an die Behandlung von LinearLinkedDictionary in der Variation SortedLinearLinkedDictionary zum Vorschein. Erinnerung: Nach "new Item()\ gilt value==null und (der entscheidende Punkt:) next==null. Informatik II { Sommersemester 1999 275 public Object put ( Object key, Object info ) throws NullPointerException { if ( key == null || info == null ) throw new NullPointerException(); if ( theKeys == null ) { theKeys = new Item(); theKeys.value = key; theInfos = new Item(); theInfos.value = info; return null; } Item currentKey = theKeys; Item currentInfo = theInfos; while ( currentKey != null ) { if ( currentKey.value == key ) return currentInfo.value; currentKey = currentKey.next; currentInfo = currentInfo.next; } Item newKey = new Item(); // *** newKey.value = key; newKey.next = theKeys; theKeys = newKey; // +++ Item newInfo = new Item(); newInfo.value = info; newInfo.next = theInfos; theInfos = newInfo; return null; } Informatik II { Sommersemester 1999 276 Ideen fur LinearLinkedDictionary.remove: Intuition zu "***\ bis "+++\ Beide Listen werden wie in get schrittweise simultan Ausgangsliste theKeys: null theKeys Nach "newKey.next = theKeys\: newKey null theKeys Nach "theKeys = newKey\: newKey theKeys Informatik II { Sommersemester 1999 null 277 Informatik II { Sommersemester 1999 278 Intuition: Realisierung: Fur den Fall "theKeys.value public Object remove ( Object key ) { if ( theKeys == null ) return null; if ( theKeys.value == key ) { Item returnValue = theInfo.value; theKeys = theKeys.next; theInfos = theInfos.next; return returnValue; } Item keyBeforeCurrent = theKeys; Item infoBeforeCurrent = theInfos; while ( keyBeforeCurrent.next != null ) { if ( keyBeforeCurrent.next.value == key ) { Object returnValue = infoBeforeCurrent.next.value; keyBeforeCurrent.next = keyBeforeCurrent.next.next; infoBeforeCurrent.next = infoBeforeCurrent.next.next; return returnValue; } } return null; } Informatik II { Sommersemester 1999 durchlaufen. Falls key dabei nicht gefunden: Wie ublich null zuruckliefern. Ansonsten: Das jeweils "richtige\ Element aus jeder der beiden Listen "ausklinken\. Das heit: { Falls das erste Element zu entfernen: Einfach theKeys auf theKeys.next bzw. theInfos auf theInfos.next umbiegen\. " { Falls ein anderes Element zu entfernen ist: Dieses Element in beiden Listen "uberbrucken\. ;! Ein Verweis zum vorhergehenden Element wird benotigt. ;! Beim Durchlauf durch die Liste mu man immer "einen Schritt zuruckbleiben\. Nach "theKeys == key\. = theKeys.next\: null theKeys Fur den Fall, da keyBeforeCurrent.next.value == key\ "z.B. im ersten Durchlauf durch die while{Schleife schon erreicht wird. Konkret nach "keyBeforeCurrent.next = keyBeforeCurrent.next.next\: keyBeforeCurrent theKeys 279 Informatik II { Sommersemester 1999 null 280 Frage: Was passiert mit den "ausgeklinkten\ Elementen (den grauen auf der letzten Folie)? Antwort: Diese Objekte sind vom Programm aus nicht mehr ansprechbar, da alle Verweise darauf "umgebogen\ wurden. Problem: Wenn laufend Elemente mit new neu erzeugt und wieder ausgeklinkt werden, besteht bald der gesamte verfugbare Speicherplatz aus solchen "Leichen\. ;! Nichts geht mehr. Losung in Java: Solche Objekte werden fruher oder spater durch einen sogenannten Garbage Collector aufgesammelt, und ihr Speicherplatz kann in new wiederverwendet werden. Garbage Collector: Unsichtbarer, unkontrollierbarer Zusatzthread, der von Zeit zu Zeit automatisch aufwacht und diese "Leichen\ einsammelt. Informatik II { Sommersemester 1999 281 Zugehorige Enumerationsklasse: public class LinearLinkedEnumeration implements Enumeration { private Item currentItem; public LinearLinkedEnumeration ( Item theItems ) { currentItem = theItems; } public bool hasMoreElements () { return currentItem != null; } public Object nextElement () throws NoSuchElementException { if ( ! hasMoreElements() ) throw new NoSuchElementException(); Object returnValue = currentItem.value; currentItem = currentItem.next; return returnValue; } } Informatik II { Sommersemester 1999 282 Konsistenzbedingung: Variation "sortierte Liste\ Verweis currentItem zeigt auf das erste noch nicht durch Methode nextElement zuruckgelieferte Element. Notwendig ist wieder einmal eine Sortierreihenfolge ;! Konstrast zu ArrayEnumeration.currentIndex! (Klasse SortedLinearLinkedDictionary): auf den Schlusselwerten. ;! Analog zu SortedArrayDictionary ein Comparator{Objekt cmp, das im Konstruktor von SortedLinearLinkedDictionary ubergeben wird. Weitere Konsistenzbedingung gegenuber LinearLinkedDictionary: theKeys ist nach der cmp{Reihenfolge aufsteigend sortiert. Beobachtung: { Methoden get und remove LinearLinkedDictionary konnen sofort von ubernommen wer- den, { ebenso LinearLinkedEnumeration, { nur Methode put mu neu implementiert werden. Informatik II { Sommersemester 1999 283 Informatik II { Sommersemester 1999 284 Ideen fur SortedLinearLinkedDictionary.put: Realisierung mit Zusatzmethode Falls das Dictionary momentan leer ist: Zu einer Liste mit einem einzelnen Element machen. Falls ansonsten key kleiner als der kleinste momentan gespeicherte Schlussel ist: ;! Wieder vorne einfugen. Ansonsten: Direkt hinter dem groten Schlussel, der kleiner als key ist. Das heit: Unmittelbar zwischen currentKey.next, falls { currentKey und cmp.isLessThan (currentKey.value, key) == true und { entweder currentKey.next == null oder cmp.isLessThan (key, currentKey.next.value) == false. Informatik II { Sommersemester 1999 285 Zusatzmethode public Object put ( Object key, Object info ) throws NullPointerException { if ( key == null || info == null ) throw new NullPointerException(); if ( theKeys == null ) { // Wie in LinearLinkedDictionary.put // (einschl. return) } if ( cmp.isLessThan(key,theKeys.value) ) { // Vorne einfuegen wie in // LinearLinkedDictionary.put // und dann return } return insert ( key, info ); } Informatik II { Sommersemester 1999 286 Intuition: SortedLinearLinkedDictionary.insert: Nach "newKey.next public Object insert ( Object key, Object info ) { Item currentKey = theKeys; Item currentInfo = theInfos; while ( currentKey.next != null && cmp.isLessThan(key,currentKey.next.value) ) { currentKey = currentKey.next; currentInfo = currentInfo.next; } if ( currentKey.next != null && key == currentKey.next.value ) return currentInfo.next.value; Item newKey = new Item(); newKey.value = key; newKey.next = currentKey.next; currentKey.next = newKey; Item newInfo = new Item(); newInfo.value = info; newInfo.next = currentInfo.next; currentInfo.next = newInfo; } Informatik II { Sommersemester 1999 SortedLinearLinkedDictionary.insert: = currentKey.next\: currentKey null theKeys newKey Nach "currentKey.next = newKey\: currentKey null theKeys newKey 287 Informatik II { Sommersemester 1999 288 Thema 13: Baumartige Implementationen von Dictionaries ("Suchbaume\) Merke: Bei einer "naiven\ Implementation von Dic- Hilfsmittel anstelle von Klasse Item: tionaries durch Arrays ergibt sich (n) Aufwand fur Suchen im Worst Case und generell fur Einfugen und Loschen im Best und Worst Case. Bei sortierten Arrays kann der Aufwand speziell fur Suchen durch binare Suche auf (log n) im Worst Case reduziert werden. Bei einer Implementation mit linearen Listen ergibt sich (1) fur das Einfugen im Best und Worst Case, aber (n) im Worst Case fur Suchen und Loschen. Bei sortierten Listen ist sogar alles (n) im Worst Case. Informatik II { Sommersemester 1999 class TreeNode { Object value; TreeNode left; TreeNode right; } Idee: Jedes Element hat nun zwei unmittelbare Nachfolger. ;! Binarer Baum anstelle einer linearen Liste. Wieder Sortierreihenfolge vorausgesetzt! 289 Intuition: Informatik II { Sommersemester 1999 290 Konsistenzbedingungen: Es gibt einen einzigen "Einstiegsknoten\, die Wurzel (root) des Baumes. value left right value left right Auf jeden Baumknoten auer der Wurzel gibt es genau einen Verweis Knoten des Baumes. value left right left oder right von einem Jeder Baumknoten ist von der Wurzel aus durch eine Sequenz von Schritten uber left- und right{ Verweise aus erreichbar. Fur jeden Baumknoten node haben alle Baumknoten im linken Nachfolgerbaum echt kleineren Schlusselwert als node.value und alle Baumknoten im rechten Nachfolgerbaum echt groeren Schlusselwert. Informatik II { Sommersemester 1999 291 Informatik II { Sommersemester 1999 292 Konsequenz: Methode get kann sich von oben nach unten von Knoten zu Knoten "durchhangeln\. In jedem Baumknoten treeNode wird treeNode.value verglichen: { gleich ;! gefunden und stop, { kleiner ;! nach links weiter, { groer ;! nach rechts weiter. key mit Java{Implementation: public class TreeDictionary { private TreeNode rootOfKeys; private TreeNode rootOfInfos; private Comparator cmp; public TreeDictionary ( Comparator cmp ) { this.cmp = cmp; } ... Methode TreeDictionary.get: public Object get ( Object key ) { TreeNode currentKey = rootOfKeys; TreeNode currentInfo = rootOfInfos; while ( true ) { if ( currentKey == null ) return null; if ( currentKey.value == key ) return currentInfo.value; if ( cmp.isLessThan(key,currentKey.value) ) { currentKey = currentKey.left; currentInfo = currentInfo.left; } else { currentKey = currentKey.right; currentInfo = currentInfo.right; } } } } Informatik II { Sommersemester 1999 293 Idee fur TreeDictionary.put: Wie in aus. get 294 Realisierung mit Zusatzmethode schrittweiser Abstieg von der Wurzel Falls key dabei gefunden: Wie u blich Information uberschreiben und alte Information zuruckliefern. Vor dem Abstieg zum jeweils nachsten Baumknoten: { Prufen, ob dieser Baumknoten uberhaupt exi- stiert. { Falls nicht: Genau an dieser Leerstelle den neuen Baumknoten einhangen. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 295 TreeDictionary.insert: public Object put ( Object key, Object info ) throws NullPointerException { if ( key == null || info == null ) throw new NullPointerException(); if ( rootOfKeys == null ) { // Wie bei LinearLinkedDictionary.put // (einschl. return-Anweisung) } return insert (key, info); } Informatik II { Sommersemester 1999 296 Zusatzmethode TreeDictionary.insert: Idee fur TreeDictionary.remove: public Object insert ( Object key, Object info ) { TreeNode currentKey = rootOfKeys; TreeNode currentInfo = rootOfInfos; while ( true ) { if ( cmp.isLessThan(key,currentKey.value) ) if ( currentKey.left == null ) { { currentKey.left = new TreeNode(); currentKey.left.value = key; currentInfo.left = new TreeNode(); currentInfo.left.value = key; return null; } else { currentKey = currentKey.left; currentInfo = currentInfo.left; } else if ( cmp.isLessThan(currentKey.value,key) ) // Analog else // d.h. falls key == currentKey.value { Object oldInfo = currentInfo.value; currentInfo.value = info; return oldInfo; } } } Informatik II { Sommersemester 1999 Das zu loschende Paar (key,info) wieder schritt- weise von oben nach unten in theKeys und theInfos simultan suchen. Wie bei Listen die Verweise currentKey und currentInfo immer einen Knoten zur uckhinken\ lassen, damit der Verweis auf den zu" entfernenden Baumknoten manipuliert werden kann. Falls nicht gefunden: Wie ublich ohne weitere Aktion null zur uckliefern. Sonst drei Falle fur die gefundenen Baumknoten currentKey und currentInfo separat betrachten: { keine unmittelbaren Nachfolgerknoten, { ein unmittelbarer Nachfolgerknoten, { zwei unmittelbare Nachfolgerknoten. 297 Fallbehandlung: hat zwei unmittelbare Nachfolger. ;! Knoten 2 null A A null Beobachtung: Wenn ein Baumknoten einen rechten Nachfolger hat (z.B. Knoten 2), dann liegt der Baumknoten mit dem nachsthoheren Schlusselwert im rechten Nachfolgerbaum und hat selbst keinen linken Nachfolger (Knoten 5). Knoten 1 Knoten 1 298 Noch zu behandeln: Der zu loschende Baumknoten Keine unmittelbaren Nachfolgerknoten ;! umstandslos loschen. currentKey Informatik II { Sommersemester 1999 null Knoten 1 Genau ein unmittelbarer Nachfolgerknoten ;! wie bei Listen durch den Nachfolgerkno- Knoten 2 E ten ersetzen. Knoten 4 Knoten 3 Knoten 1 Knoten 1 currentKey Knoten 3 Knoten 2 C null Knoten 3 C ;! A D B Knoten 5 A B null A C B Informatik II { Sommersemester 1999 299 Informatik II { Sommersemester 1999 300 Losung: Weiteren Verweis beforeNextHigherKey bis zum unmittelbaren Vorganger von Knoten 5 weiter absteigen lassen. Wert value von Knoten 2 wird mit dem Inhalt von Knoten 5 uberschrieben. Knoten 5 wird anstelle von Knoten 2 gema 2. Fall ausgeklinkt. Konsequenzen: Genau die richtigen Werte verbleiben im Baum. Die Konsistenzbedingungen fur die Baumstruktur und die Sortierreihenfolge werden aufrechterhalten. Knoten 1 beforeCurrentKey Knoten 2 E Knoten 4 Knoten 3 beforeNextHigherKey A D B Knoten 6 Knoten 5 F null C Informatik II { Sommersemester 1999 301 Enumeration auf binaren Baumen: Durch Fadelung der Baumknoten. Informatik II { Sommersemester 1999 302 Genauere Erlauterungen: Jeder Baum hat eine weitere Objektvariable realRight vom Typ boolean. Bedeutung: realRight null null null null null null null == true, falls right auf einen "richtigen\ Nachfolgerknoten zeigt oder right == null ist (durchgezogene Pfeile in der Zeichnung auf der letzten Folie). null null Es gilt right ten. Erste Erlauterung: Abgesehen vom Knoten mit dem allerhochsten Schlusselwert zeigt Objektvariable right bei jedem Baumknoten auf einen anderen Baumknoten. Der Zielknoten eines right{Verweises hat immer hoheren Schlusselwert als der Knoten, von dem der right{Verweis ausgeht. Die neuen Ruckwartsverweise zeigen sogar immer auf den Baumknoten mit dem nachsthoheren Schlusselwert. Informatik II { Sommersemester 1999 303 == null nur beim allerletzten Kno- Suchen, Einfugen, Loschen: Verweis nicht weiter verfolgt, falls realRight right wird == false. Beim Einfugen und Loschen mu der betroe- ne Baumknoten korrekt "ein-/ausgefadelt\ werden (hier nicht genauer behandelt). Informatik II { Sommersemester 1999 304 Java{Implementation: Enumeration in Sortierreihenfolge: Allererster Baumknoten: Soweit wie moglich von der Wurzel aus nach links absteigen. Jeweils nachster Baumknoten nach dem aktuellen Baumknoten currentNode: { Zuerst uber right einen Schritt weitergehen. { Falls das ein "echter\ Verweis auf einen Nachfolger war (durchgezogener Pfeil): Danach noch soweit wie moglich nach links weiter absteigen. Konsistenzbedingung: Wie bei LinearLinkedDictionary. null null null null null null null public class TreeEnumeration implements Enumeration { private TreeNode currentNode; public TreeEnumeration ( TreeNode rootOfTree ) { currentNode = rootOfTree; while ( currentNode.left != null ) currentNode = currentNode.left; } public boolean hasMoreElements () { return currentNode != null; } public Object nextElement () throws NoSuchElementException { if ( ! hasMoreElements() ) throw new NoSuchElementException(); Object returnValue = currentNode.value; boolean descendLeft = currentNode.realRight; currentNode = currentNode.right; if ( currentNode != null && descendLeft ) while ( currentNode.left != null ) currentNode = currentNode.left; return returnValue; } null null } Informatik II { Sommersemester 1999 305 Frage: Was ist denn nun gewonnen durch U bergang von linearer zu binarer Struktur? Antwort: Zunachst einmal noch gar nichts, weil der Baum im Worst Case zu einer linearen Liste entarten kann. Informatik II { Sommersemester 1999 306 Erinnerung: Ein balancierter Baum hat Hohe log2 n. ;! Eine einzelne Such-, Einfuge- oder Loschoperation kostet (log n) Zeit. Knoten 1 null Knoten 2 null Knoten 3 null null null null null null null null null null null null null null null null null Aber: Jede Einfuge- oder Loschoperation kann den Baum potentiell ein kleines Stuck weiter aus der Balance bringen. ;! Auf Dauer doch wieder (n) im Worst Case. Knoten n null Informatik II { Sommersemester 1999 null 307 Informatik II { Sommersemester 1999 308 Idee: Wenn man es schaen wurde, beim Einfugen und Loschen eine gewisse Balance zu halten, so da der Zusatzaufwand fur dieses Balancehalten aber immer noch (log n) pro Einfuge-/Loschoperation bleibt, dann ist (log n) pro Such-/Einfuge-/Loschoperation bis in alle Ewigkeit garantiert (n die momentane Groe des Dictionaries zum Zeitpunkt der Operation). Denkbare Kandidaten (inspiriert aus dem optimal balancierten Fall): Fur jeden Baumknoten unterscheiden sich die Knotenzahlen im linken und rechten Nachfolgerbaum (A und B ) nicht sonderlich. Die Hohen von A und B unterscheiden sich nicht sonderlich. Problem: Optimale Balance kann man anscheinend nicht durchhalten. ;! Gesucht ist eine schwachere Denition von Balance. Stark genug, um (log n) pro Operation zu garantieren. Schwach genug, um mit (log n) Aufwand pro Operation aufrechterhalten zu werden. Informatik II { Sommersemester 1999 A 309 Informatik II { Sommersemester 1999 B 310 Tiefe Einsicht: Die Eigenschaft, da sich fur jeden Baumknoten die Hohen der beiden Nachfolgerbaume im Betrag um maximal 1 unterscheiden, ist geeignet. Vorabbetrachtung: In einem Baum mit n Knoten gibt Stichwort in der Literatur: Ein Suchbaum mit dieser Eigenschaft ist ein AVL{Baum. Beweis: Mit vollstandiger Induktion uber die Knotenzahl n 1. Behauptung: Ein AVL{Baum mit n Knoten hat Hohe (log n). n = 1: 1 Blatt, kein innerer Knoten. n > 1: Sowohl der linke als auch der rechte Teilbaum Beweis: Nachste sechs Folien. Informatik II { Sommersemester 1999 311 es mehr Blatter als innere Knoten (d.h. Knoten, die keine Blatter sind). der Wurzel hat jeweils fur sich mehr Blatter als innere Knoten. ;! Fur beide Teilbaume zusammengezahlt ist die Blatterzahl um mindestens 2 hoher als die Anzahl innerer Knoten. ;! Zusammen mit der Wurzel immer noch mehr Blatter als innere Knoten. Informatik II { Sommersemester 1999 312 Nun Beweisansatz fur die Behauptung, da AVL{ Baume logarithmische Hohe haben Zunachst: Besser als O(log n) geht nicht, da ein optimal balancierter Baum mit n Knoten (vgl. Thema 10) Hohe dlog2(n)e hat und kein anderer binarer Baum mit n Knoten geringere Hohe hat. Fortsetzung Beweis: Zu gegebener Hohe h betrachte die AVL{Baume mit Hohe h, die minimale Knotenzahl haben. ;! Heien in der Literatur Fibonacci{Baume. Beobachtung: Bei jedem Baumknoten unterscheiden sich in diesem Fall die Hohen beider Nachfolgerbaume im Betrag um genau 1. (Sonst konnte man noch einen geeignet gewahlten Knoten wegnehmen, ohne da sich die Gesamthohe h verringert oder die AVL{Eigenschaft verletzt wird.) ;! Es reicht, O(log n) anstelle von (log n) zu zeigen. Informatik II { Sommersemester 1999 313 Konsequenz: Rekursionsformel fur die Knotenzahl n(h) eines Fibonacci{Baumes mit Hohe h. 81 < n(h) = : 2 1 + n(h ; 1) + n(h ; 2) fur h = 0; fur h = 1; fur h > 1: 314 Zwischenstand: AVL{Baume mit Hohe h haben mindestens fib(h) Knoten. Aber: Eigentlich interessierte uns nicht die Minimalknotenzahl in Abhangigkeit von Hilfsbehauptung: Fur alle h 2 N gilt fib(h) n(h). Begrundung: Vergleich der beiden Rekursionsformeln fur n(h) bzw. fib(h). Bemerkung: Eine einfache vollstandige Induktion zeigt zudem n(h) 3 fib(h) ; 1. ;! Daher Begrisbildung Fibonacci{Baum. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 315 der Hohe, sondern umgekehrt die Maximalhohe in Abhangigkeit von der Knotenzahl. Also: Umkehrabbildung betrachten. Kleines technisches Problem: Es gibt nicht um- gekehrt zu jeder Knotenzahl m eine Hohe h mit n(h) = m. Losung: Fur m 2 N sei H (m) die grote Zahl h mit n(h) = n(H (m)) m. ;! Die Hohe eines AVL{Baumes mit m Knoten ist hochstens H (m). Informatik II { Sommersemester 1999 316 Bisher erreicht: Abschatzung (log m) im Best und Worst Case fur die Hohe von AVL{Baumen mit m Zwischenstand auf der letzten Folie besagte: n(h) fib(h). Knoten. Erinnerung: fib(k) 2 ((1:618:::)k). Fehlt noch: Realisierungen von put und remove, die ;! Es gibt Konstanten m0 2 N und c > 0, so da fur alle m m0 gilt: jeden AVL{Baum garantiert wieder in einen AVL{Baum uberfuhren. m n(H (m)) fib(H (m)) c (1:618:::)H (m) Beobachtung: Wenn ein einziger Knoten eingefugt oder entfernt ;! H (m) log(1:618:::)( 1c m) wird, kann die Hohendierenz von linkem und rechtem Teilbaum nirgendwo um mehr als 1 verletzt werden, und das auch nur entlang des Baumpfades von der Wurzel bis zum eingefugten bzw. geloschten Knoten. ;! H (m) 2 O(log m) ;! Beweis fertig. Informatik II { Sommersemester 1999 317 Informatik II { Sommersemester 1999 318 Fall I: A ist mindestens so hoch wie B . Basistechnik: Rotation an einem einzelnen Baumknoten ;! Einfachrotation: Annahmen (ohne Beschrankung der Allgemeinheit): Die AVL{Eigenschaft ist fur alle Knoten in A, B und C erfullt. Der linke Nachfolgerbaum von Knoten 1 (also "Knoten 2\ + A + B ) hat eine um 2 groere Hohe als C . Knoten 1 Knoten 2 Knoten 1 C A Knoten 1 Knoten 2 B A B C Ergebnis: Knoten 1 und alle seine unmittelbaren und mittelbaren Nachfolger erfullen die AVL{Eigenschaft. Knoten 2 C A Informatik II { Sommersemester 1999 B 319 Informatik II { Sommersemester 1999 320 Fall II: ("Knoten 3\ + B + C ) ist um 1 hoher als A. ;! Doppelrotation: AVL{Baumen: Zuerst neues Element einfugen bzw. altes Element Knoten 1 loschen wie bei TreeDictionary. Knoten 3 Knoten 2 Danach jeweils AVL{Eigenschaft wieder an allen Knoten 2 Knoten herstellen. Knoten 1 Erinnerung: Nur die Knoten auf dem Baumpfad zum D eingefugten/geloschten Element sind betroen. Knoten 3 A A B Anwendung beim Einfugen und Loschen in B C D { Der Pfad wird von unten nach oben (also C "ruckwarts\) durchlaufen. { Jeder Knoten, an dem die AVL{Eigenschaft verletzt ist, wird durch Einfach- bzw. Doppelrotation wieder in Balance gebracht. Ergebnis: Wieder AVL{Eigenschaft uberall erfullt. Informatik II { Sommersemester 1999 Konkrete Vorgehensweise: 321 Informatik II { Sommersemester 1999 322 Technisches Problem: Beobachtung: Woher sind bei einem Baumknoten die Hohen der Bei einer Rotation andern sich diese Dierenzen beiden Nachfolgerbaume bekannt? Jeweils bei Bedarf berechnen wurde ja wohl alle Bemuhungen um etwas Besseres als (n) pro Operation zunichte machen. Hilfreiche Einsicht: Die Hohen werden eigentlich gar nicht gebraucht, sondern nur die Dierenz von linkem und rechtem Nachfolgerbaum. nur in den 2 bzw. 3 rotierten Knoten sowie in den unmittelbaren und mittelbaren Vorgangerknoten. Unter den rotierten Knoten sind die A nderungen nach einfachen Regeln und in (1) Zeit berechenbar. Die A nderungen bei den hoheren Knoten konnen aufgeschoben und beim Durchlaufen des Baumpfades von unten zur Wurzel "mitgeschleppt\ werden (Details hier nicht behandelt). Diese Dierenz kann fur jeden Knoten einfach als zusatzliche Objektvariable gespeichert werden. Informatik II { Sommersemester 1999 323 Informatik II { Sommersemester 1999 324 Beispiel fur die einfachen (1){ Regeln fur die Berechnung der Hohendierenz bei den rotierten Knoten: Einfachrotation mit Hohenverhaltnissen h(A) = h(B ) + 1 = h(C ) + 1. +2 +1 Knoten 1 Knoten 2 Knoten 2 A B A B Bei einer "naiven\ Implementation von Dic- tionaries durch binare Baume ergibt sich doch wieder (n) Aufwand fur Suchen, Einfugen und Loschen im Worst Case. Bei "halbwegs\ balancierten Baumen (z.B. AVL{Baumen) reduziert sich dieser Aufwand zu (log n). Bei AVL{Baumen kann die denierende Balanceeigenschaft auch in (log n) Zeit pro Einfuge- und Loschoperation aufrechterhalten werden. Insgesamt kann man Dictionaries also in einer Form implementieren, so da Suchen, Einfugen und Loschen jeweils (log n) Zeit benotigt. 0 Knoten 1 C Merke: 0 C Andere Falle: Analog. Informatik II { Sommersemester 1999 325 Informatik II { Sommersemester 1999 326 Thema 14: Vielwegbaume Exkurs: Hintergrundspeicher Interessierte Zusatzfrage: Im eigentlichen Datenspeicher eines Computers Bisher haben wir nur binare Baume betrachtet. Waren Baume mit potentiell mehr als 2 Nachfolgern pro Knoten nicht besser? Antworten: menfunktionen zu beliebigen Basen > 1 asymptotisch aquivalent sind (vgl. Thema 8). Auch bei den Proportionalitatsfaktoren ist nicht klar, welche Basis gunstig ist. (Suchschritt pro Baumknoten wird aufwendiger!) Asymptotisch bringt es gar nichts, da alle Logarith- Aber: Vielwegbaume sind interessant fur den Fall, da die Datenmenge zu gro fur den Hauptspeicher ist. Informatik II { Sommersemester 1999 327 (Hauptspeicher) werden die Daten nur temporar gehalten. Spatestens, wenn der Computer heruntergefahren wird, ist der Inhalt des Hauptspeichers verloren. Fur permanente Datenhaltung sind Hintergrundspeicher zustandig. U bliches Medium: Festplatten. Entscheidender Punkt fur das Weitere: { Daten werden zwischen Haupt- und Hintergrundspeicher nicht Bit fur Bit oder Byte fur Byte transferiert, { sondern in groeren Blocken (Seiten). { Momentan ublich: 1.024, 2.048, 4.096 oder 8.192 Byte pro Seite. Informatik II { Sommersemester 1999 328 Problem: In diesem Abschnitt der Vorlesung (Thema 14): Die Laufzeit fur Datentransfer von oder auf Hinter- Behandlung der wichtigsten Datenstruktur fur dieses Momentan typischerweise: Ungefahr Bedeutung: B{Baume (bzw. Variationen von B{ Konsequenz: Aber: Nur das abstrakte Prinzip von B{Baumen grundspeicher ist um Groenordnungen groer als die Laufzeit fur interne Elementaroperationen. Szenario: B{Baume. Baumen) sind das Ruckgrat jedes ernstzunehmenden Datenbanksystems. Faktor 10.000 | 1.000.000. Minimierung der Zugrie auf den Hintergrundspeicher pro Such-, Einfuge und Loschoperation ist in diesem Szenario absolut vordringliches Optimierungsziel. wird hier behandelt. Warum: Die exakten Details sind zu umfangreich und komplex. Die bisher betrachteten Elementaroperationen fallen im Vergleich nicht weiter ins Gewicht. Informatik II { Sommersemester 1999 329 Idee: Jeder Baumknoten kann bis zu k verschiedene Ele- mente speichern. Die Anzahl der unmittelbaren Nachfolger ist um genau 1 groer als die Anzahl der gespeicherten Elemente. Die Konstante k wird so gewahlt, da k Elemente und k + 1 Verweise zusammen gerade noch auf eine Seite passen. Informatik II { Sommersemester 1999 Konsistenzbedingungen (nur am Beispiel): Fur jeden Schlussel x aus A gilt x < a. Fur jeden Schlussel x aus B gilt a < x < b. Fur jeden Schlussel x aus C gilt b < x < c. ... Fur jeden Schlussel x aus F gilt e < x < f . Fur jeden Schlussel x aus G gilt f < x. Illustration: Einzelner Baumknoten mit k = 9, Schlusselwerten a, b, c,: : :, f und Nachfolgerbaumen A; : : : ; G. a b c d e 330 a b c d e f null null null f A B C D E F G null null null A B C D Informatik II { Sommersemester 1999 E F G 331 Informatik II { Sommersemester 1999 332 Konsequenz aus den Konsistenzbedingungen: Wie bei TreeDictionary konnen sich get, put und von oben nach unten zur richtigen Stelle im Baum "durchhangeln\. In jedem Baumknoten mu der Suchschlussel mit bis zu k Schlusselwerten verglichen werden. Der "richtige\ unmittelbare Nachfolgerknoten kann allein durch Vergleich des Suchschlussels mit den Schlusselwerten des Baumknotens ermittelt werden (d.h. ohne Ansehen der Nachfolgerknoten). remove Ergebnis: Herausforderung: Gleichzeitig folgende Ziele errei- chen... Alle Baumknoten ausreichend ausgelastet. Hohe wie bei AVL{Baumen logarithmisch beschrankt. Aufrechterhaltung dieser beiden Eigenschaften bei Einfugen und Loschen erfordert den Zugri auf moglichst wenige (und immer noch nur logarithmische viele) weitere Baumknoten. Guter Kompromi: B{Baume Die Anzahl der Zugrie auf den Hintergrundspeicher Denition: Ein B{Baum der Ordnung k (k gerade) ist Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 kann sich in Abhangigkeit von k massiv reduzieren. Voraussetzung: Die einzelnen Baumknoten sind gut ausgelastet\, das heit enthalten nicht wesentlich "weniger als k Schlusselwerte. 333 ein Vielwegsuchbaum wie oben beschrieben, so da alle Blatter gleiche Hohe haben, jeder Baumknoten auer der Wurzel mindestens k=2 und hochstens k Schlusselwerte enthalt und die Wurzel mindestens einen und hochstens k Schlusselwerte enthalt. 334 Behauptung: Die Hohe eines B{Baumes der Ordnung k mit n gespeicherten Schlusselwerten ist in (log n). Beweis der Hilfsbehauptung: Vollstandige Induktion uber h. Notation: H (T ) bezeichnet die Hohe des Baumes T . hochstens k Schlusselwerte in der Wurzel (Hohe 0). ;! Mindestens 2 = 2 (: : :)0 und hochstens k + 1 = (k + 1)1 Knoten auf Hohe 1. Hilfsbehauptung: Fur h 2 f1; : : : ; H (T )g gibt es in einem B{Baum T der Ordnung k mindestens h ; 1 2 k2 + 1 Induktionsverankerung h = 1: Mindestens ein und Induktionsschritt (h ; 1) ;! h > 1: Jeder Knoten auf Hohe h ; 1 > 0 hat mindestens k2 + 1 und hochstens k + 1 unmittelbare Nachfolger. ;! Mindestens und hochstens (k + 1)h Knoten. k 2 2 k h ; 23 k h ; 1 5 = 2 + 1 + 1 42 + 1 2 2 und hochstens (k + 1) (k + 1)h ; 1 = (k + 1)h Knoten auf Hohe h. Informatik II { Sommersemester 1999 335 Informatik II { Sommersemester 1999 336 Konsequenz: In einem B{Baum T der Ordnung k enthalt jede Hohenstufe h 2 f1; : : : ; H (T )g minde k h ; 1 stens k 2 +1 und jede Hohenstufe h 2 f0; : : : ; H (T )g hochstens k (k + 1)h Schlusselwerte. Begrundung: Obere und untere Abschatzung aus der Hilfsbehauptung fur die Anzahl Baumknoten pro Hohenstufe mit den oberen und unteren Schranken (k=2 bzw. k) fur die Anzahl Schlusselwerte pro Baumknoten multiplizieren. Nachstes Ziel: Darauf aufbauend obere und untere Abschatzun- gen fur die Gesamtzahl n(T ) von Schlusselwerten in einem B{Baum T der Ordnung k in Abhangigkeit von der Hohe berechnen. Durch Umstellung Abschatzungen fur die Hohe in Abhangigkeit von der Knotenzahl nden. Informatik II { Sommersemester 1999 337 HX (T ) h=0 k (k + 1)h = k HX (T ) HX (T ) k +1 h;1 h=1 2 H (X T );1 = 1+k k +1 h 2 h=0 (Formel fur geometrische Folgen:) ; k + 1H(T ) ; 1 = 1 + k 2; k 2 +1 ;1 = 1+2 " # k + 1 H (T ); 1 2 H(T ) = 2 k2 + 1 ;1 Informatik II { Sommersemester 1999 h=0 (k + 1)h 338 ;1 ;! H (T ) log( k +1) n(T ) + 1 2 H (T )+1 = k (k +(k1)+ 1) ; 1; 1 = (k + 1)H (T )+1 H(T ) n(T ) 2 k2 + 1 (Formel fur geometrische Folgen:) Informatik II { Sommersemester 1999 n(T ) 1 + k Umgestellt jeweils nach der Hohe H (T ): Obere Abschatzung: n(T ) Untere Abschatzung: 2 n(T ) (k + 1)H (T )+1 ; 1 ;! H (T ) log(k+1) (n(T ) + 1) ; 1 ;1 339 Informatik II { Sommersemester 1999 340 Stand soweit: H (T ) 2 (log n(T )). Umrechnung der Abschatzungskonstanten in den 2{ Logarithmus: 21 log(k+1) (n(T )) 1 2 log2(k + 1) log2(n(T )) H (T ) log( k +1) " n(T ) + 1 2 2 2 log2 # ; 2 log 1(k + 1) log2(n(T )) log2 k2 + 1 2 ;1 Realistische Groenordnungen fur k: k = 100 ;! [:::] 10%. k = 1000 ;! [:::] 6%. log( k +1)(n(T )) = Erinnerung (Thema 10): Die kleinstmogliche Hohe eines binaren Baumes mit n Knoten tritt bei totaler Balancierung auf, namlich log2(n). Die grotmogliche Hohe eines B{Baumes unterscheidet sich davon etwa um Faktor 1= log2(k + 1). Die grot- und kleinstmogliche Hohe eines B{ Baumes unterscheiden sich maximal um den Faktor H (T ) log(k+1) (n(T ) + 1) ; 1 = Auswertung: ;1k + 1 log2(n(T )) 2 Informatik II { Sommersemester 1999 341 Ideen fur BTreeDictionary.put: Informatik II { Sommersemester 1999 342 Intuition: "g\ in ein volles Blatt einfugen Suche von der Wurzel aus das Blatt, in das der neue (gestrichelter Pfeil: null{Verweis) Schlusselwert hineingehoren wurde. a b c p q d r Falls weniger als k Werte momentan in diesem Blatt gespeichert sind: einfach einfugen und fertig. e f h j i k l m n o Ansonsten: Blatt in zwei Teile zerlegen und den Schlusselwert (Median) zum nachst"hmittleren\ oheren Baumknoten weiterreichen. a b c d j p q r Falls der auch schon voll war: Rekursiv weiter hochsteigen im B{Baum. Informatik II { Sommersemester 1999 e 343 f g h i Informatik II { Sommersemester 1999 k l m n o 344 Falls beim rekursiven Hochsteigen die Wurzel erreicht wird und die Wurzel ebenfalls voll ist: Intuition: "d\ in die volle Wurzel einfugen Wurzel wird ebenfalls in zwei Teile zerlegt. Neue Wurzel wird angelegt. Der mittlere Schlusselwert wird als einziger a Schlusselwert in der neuen Wurzel gespeichert. b c e f g h i j k g h i j k f ;! Daher die notwendige Ausnahme, da die Wurzel nicht mindestens k=2 Schlusselwerte enthalten mu. a b c d e Beachte: Nur wenn entlang des Baumpfades von der Einfugestelle bis zur Wurzel alle Knoten (einschlielich Wurzel) voll sind, vergroert sich die Hohe des Baumes. ;! Also im Normalfall relativ selten. Informatik II { Sommersemester 1999 345 Ideen fur BTreeDictionary.remove: Zu loschenden Schlusselwert wie ublich absteigend von der Wurzel aus suchen und loschen. Falls danach noch mindestens k=2 Schlusselwerte im betroenen Knoten sind: Fertig. Ansonsten: Umkehrung der Zerlegungsoperation, d.h. Verschmelzung von "Geschwisterknoten\. Insbesondere: Ein Schlusselwert wird aus dem gemeinsamen unmittelbaren Vorganger heruntergezogen. Falls der unmittelbare Vorganger nur k=2 Schlusselwerte hatte: ;! Analog zum Einfugen soweit wie notig im Baum hochgehen und auf jeder Stufe eine solche Verschmelzung durchfuhren. Falls dabei die Wurzel leer wird: ;! Wurzel wird geloscht. ;! Einzige Situation, in der die Hohe des B{Baumes reduziert wird. Informatik II { Sommersemester 1999 347 Informatik II { Sommersemester 1999 346 Intuition zum Verschmelzen: "m\ loschen a e f g h b c d j i a e b f g Informatik II { Sommersemester 1999 p q r k l c d p q r h j k l i m n n o o 348 Thema 15: Hash{Tabellen Merke: Bei der Verwaltung von Daten auf dem Hin- Szenario: tergrundspeicher ist nicht nur die Asymptotik praktisch von Bedeutung, sondern auch die genaue Zahl von Speicherzugrien. Aus diesem Grund sind hier Vielwegbaume interessant, in denen jeder Knoten eine Speicherseite ausmacht. B{Baume bieten eine Mindestgarantie fur die Auslastung jedes einzelnen Baumknotens (=Speicherseite). Daraus folgen im Verhaltnis zu binaren Baumen sehr gunstige Konstanten fur die logarithmische Asymptotik: Die maximale Hohe eines B{Baumes mit n Knoten ist immer noch um einen (von der Ordnung des B{Baumes abhangigen) Faktor kleiner als die minimale Hohe eines binaren Baumes. Informatik II { Sommersemester 1999 Nach dem Aufbau des Dictionaries sollen keine Elemente mehr eingefugt oder geloscht werden. Vor Aufbau des Dictionaries ist schon die Gesamtzahl von zu speichernden Elementen bekannt. ;! Statisches Dictionary. Bisheriges Resultat: (log n) pro Operation im Worst Case (Thema 13 und 14). Keine Perspektive fur etwas Besseres als (log n) im Average Case fur "realistische\ Haugkeitsverteilungen. 349 In diesem Abschnitt: Eine Datenstruktur auf Arraybasis, fur die im Worst Informatik II { Sommersemester 1999 350 Fahrplan: Case nur (n) Aufwand pro Einfugeoperation beim Aufbau bzw. pro Suchoperation garantiert werden kann. Durch eine "pseudozufallige\ Streuung (hashing) der Elemente uber das Array zeigt jede "nichtpathologische\ Haugkeitsverteilung erfahrungsgema ungefahr dasselbe Laufzeitverhalten wie eine reine Zufallsverteilung. Konsequenz: { Man braucht sich im Average Case keine Gedanken um die genaue Haugkeitsverteilung zu machen, { sondern kann der Analyse einfach den idealisierten Fall einer Zufallsverteilung zugrundelegen. Ergebnis wird sein: In diesem speziellen Fall von Average Case gilt (1). Zuerst das Grundkonzept auf abstrakter Ebene be- Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 351 trachten (Durststrecke!). Dann Zielvorstellungen uberlegen, wie dieses Grundkonzept sinnvoll mit Leben zu fullen ist. Schlielich konkrete Beispiele zum Thema "mit Leben fullen\ betrachten. 352 Grundkonzept: Konsistenzbedingungen: Fur n 2 N zu speichernde Elemente werden Arrays theKeys und theInfos mit Indexbereich 0 : : : m ; 1, eingerichtet: m 2 N , m n. Falls an Index i 2 f0; : : : ; m ; 1g momentan Es gibt eine Folge von Funktionen f0; f1; f2; Sei x ein momentan gespeicherter Schlusselwert, und sei i 2 f0; : : : ; m ; 1g der Index von x, das : : : ; fm;1, von denen jede den Wertebereich fur Schlusselwerte auf f0; : : : ; m ; 1g abbildet, und zwar so, da fi(x) != fj (x) fur alle potentiellen Schlusselwerte x und alle i; j 2 f0; : : : ; m ; 1g, i= 6 j , ist. ;! Fur jeden momentan gespeicherten Schlusselwert x gibt es genau ein i 2 f0; : : : ; m ; 1g, so da theKeys[fi (x)] == 353 Idee fur HashDictionary.get: ist, durch. dabei auftritt: fi(x)] zuruckliefern und fertig. Falls statt dessen theKeys[fi(x)] auftritt: == null ;! Schlusselwert x ist gema Konsistenzbe- Informatik II { Sommersemester 1999 354 ;! Schlusselwert und Information in theKeys[fi(x)] dingungen momentan nicht gespeichert. bzw. theInfos[fi (x)] ablegen. ;! Einfach null zuruckliefern und fertig. Informatik II { Sommersemester 1999 != null. ist, durchgehen. Falls theKeys[fi(x)] == x dabei auftritt: theInfos[fi (x)] mit Argument info u berschreiben, alten Wert zuruckliefern und fertig. Falls statt dessen theKeys[fi(x)] == null auftritt: ;! Schlusselwert x ist gema Konsistenzbedingungen momentan nicht gespeichert. f0(x); f1(x); f2(x); : : : soweit, wie es notig == x fj (x)] theKeys[ Idee fur HashDictionary.put: Wieder f0(x); f1(x); f2(x); : : : soweit, wie es notig Fur einen gegebenen Schlusselwert x gehe theInfos[ heit theKeys[fi (x)] == x. Fur alle j 2 f0; : : : ; i ; 1g gilt dann x ist. Informatik II { Sommersemester 1999 Falls theKeys[fi(x)] kein Element in den Arrays gespeichert ist, gilt theKeys[i] == null. Methode HashDictionary.remove: Ist im eingangs formulierten Szenario irrelevant. 355 Informatik II { Sommersemester 1999 356 Frage: Was will man eigentlich erreichen? Oen: Konkrete Denition der Funktionen f0; f1; f2; : : : Primitives Beispiel: fi(x) = i fur alle potentiellen Schlusselwerte x. Klare Antwort: Den Wert i mit theKeys[fi(x)] == x oder theKeys[fi(x)] == null moglichst klein halten (zumindest im Durchschnitt). Beim Einfugen des i{ten Elements x sind Vorbetrachtung: Wie mu fi deniert sein, damit fur zwei beliebige Schlusselwerte x und y die Wahrscheinlichkeit einer Kollision fi(x) = fi(y) moglichst klein ;! Einfugen von n m Elementen kostet Lauf- Einkleidung in eine weniger abstrakte Fragestellung: Trauriges Resultat: f0(x); : : : ; fi;2(x) schon besetzt. zeit 2 n ! X i=1 i = n(n + 1) 2 ; = n2 Wenn mit get nicht ausgerechnet immer nur auf ein paar wenige, fruh eingefugte Elemente zugegrien wird, dann kostet get auch im Average Case (n) Laufzeit. Informatik II { Sommersemester 1999 357 Wie gro ist die Wahrscheinlichkeit, da zwei beliebige Leute am gleichen Datum (Schaltjahre ignoriert) Geburtstag haben? Naheliegende Antwort: Es gibt 365 365 mogliche Kombinationen. Davon gibt es 365 Kombinationen mit gleichem Datum. 1 ;! 365 Informatik II { Sommersemester 1999 358 Anschlufrage: Wie mute die Wahrscheinlichkeits- Kleines Problem: verteilung sein, damit gleiches Geburtsdatum moglichst unwahrscheinlich wird? Die Rechnung ist richtig. Aber die Antwort ist falsch! Ansatz: Warum: Die implizite Voraussetzung, da alle Geburtsdaten 1:1:;31:12: gleichwahrscheinlich sind, stimmt nicht. Im Fruhjahr werden mehr Kinder geboren als im Herbst. Frage: A ndert sich dadurch wirklich etwas am Ergebnis? Trockene Antwort durch Extrembeispiel: Alle Kinder werden am 1:1: geboren. 1 ;! Wahrscheinlichkeit 1 statt 365 Informatik II { Sommersemester 1999 wird? 359 Reellwertige Variable x1; x2; : : : ; x365 2 [0; 1]. Forderung: x1 + x2 + + x365 = 1. Interpretation: xi ist die Wahscheinlichkeit, da eine Person am Datum Nr. i Geburtstag hat. ;! x2i ist die Wahrscheinlichkeit, da beide Personen am Tag i Geburtstag haben. ;! x21 + x22 + + x2365 ist die Wahrscheinlichkeit, da beide Personen an irgendeinem Tag zugleich Geburtstag haben. Ziel: Werte fur x1; : : : ; x365 so bestimmen, da x21 + x22 + + x2365 minimal wird. Informatik II { Sommersemester 1999 360 Behauptung: Das globale Minimum wird bei x1 = x2 = = x365 = 1=365 angenommen. Beweis: Durch Widerspruch, das heit, die exakt gegenteilige Behauptung wird zum Widerspruch gefuhrt. Gegenteilige Behauptung: Lat sich ohne Beschrankung der Allgemeinheit vereinfachen zu x1 6= x2 . Wegen y + y + x3 + x4 + + x365 = 1 mit y := (x1 + x2)=2 reicht zu zeigen: Wenn x1 und x2 beide durch y ersetzt werden, ergibt sich eine echte Verbesserung. Ansatz mit 1. Binomischer Formel: x + x 2 2 2 y +y = 2 12 2 ; = 21 x21 + 2 x1 x2 + x22 Informatik II { Sommersemester 1999 Umgestellt: 2 x1 x2 < x21 + x22 Zusammengefat mit 2. Binomischer Formel: ( x2 ; x1 )2 > 0 Aber: (x2 ; x1)2 > 0 folgt sofort aus der Widerspruchsannahme x1 6= x2. ;! x21 + x22 + x23 + + x2365 > y2 + y2 + x33 + + x2365 ;! Beweis fertig. 361 Zuruck zu Hash{Tabellen und f0: Informatik II { Sommersemester 1999 362 Idealisiertes Modell zur asymptotischen Stand soweit: Ideal ware es, wenn jedes fi al- le Schlusselwerte uniform uber den Indexbereich f0; : : : ; m ; 1g "verstreuen\ wurde. Problem: { Das wurde eine echte Zufallsstreuung erfordern. { Wenn man die gespeicherten Schlusselwerte mittels f0; f1; f2; : : : wiedernden will, mussen diese Funktionen aber 100% deterministisch sein. Abgeschwachte Zielsetzung: Finde Funktionen f0; f1; f2; : : :, die { 100% deterministisch sind, { aber einer uniformen Zufallsverteilung Analyse: Seien i; j 2 f0; : : : ; m ; 1g. Die Wahrscheinlichkeit, da fi(x) = j ist, ist gleich 1=m, und zwar unabhangig von allen anderen Werten fj (y) mit j 6= i und/oder y 6= x, abgesehen davon, da weiterhin fi(x) 6= fj (x) fur alle i 6= j gelten soll. (Hintergrund: Vorlesungen zu Stochastik oder Statistik, Stichwort bedingte Wahrscheinlichkeiten.) Behauptung: Einfugen und Suchen von n m Elementen kostet in diesem idealisierten Modell (1) Laufzeit pro Operation. "zum Verwechseln\ ahnlich sehen. Informatik II { Sommersemester 1999 Also zu zeigen: 1 ; x2 + 2 x x + x2 < x2 + x2 1 2 1 2 1 2 2 363 Informatik II { Sommersemester 1999 364 Einschub: Was sagt diese Behauptung eigentlich aus? Also: Analogie aus der Physik: Fallgesetz (1) Laufzeit ist 100% korrekt fur das idealisierte Liefert 100% korrekte Berechnungen fur den ideali- sierten Fall eines Massepunkts ohne Ausdehnung in einem totalen Vakuum unter einem homogenen Gravitationsfeld und ohne die Wirkung weiterer Krafte. Praktisch 100% korrekte Berechnungen fur Experimente unter "Laborbedingungen\. Leidlich korrekte Berechnungen fur Szenarien, in denen andere Einusse eine geringe Rolle spielen (Ballistik, Flugbahnen im Weltraum...). Modell. ;! Noch zu beweisen. Auch noch praktisch korrekt, falls f0; f1; f2; : : : wie uniforme Zufallsverteilungen "aussehen\. Aber allgemein lat sich fur beliebige f0; f1; f2; : : : nichts daraus folgern. ;! Siehe primitives Beispiel oben. Vollig unbrauchbare Berechnungen fur Situationen mit "alltagstypischer\ Komplexitat (Flug einer Vogelfeder im Wind). Informatik II { Sommersemester 1999 365 Beweis der Behauptung: Einfugen und Suchen in (1) Laufzeit im Average Case. Einfugen eines Schlusselwertes x und spateres er- folgreiches Suchen von x kosten asymptotisch gleich viel. ;! Einfugen mu im weiteren nicht betrachtet werden. Erfolgreiches und erfolgloses Suchen eines nichtge- speicherten Schlusselwertes sind verschiedene Szenarien. ;! Fallunterscheidung. Informatik II { Sommersemester 1999 366 Teilbehauptung I: Erfolgreiche Suche erfordert im Durchschnitt die Auswertung von 1 1 ; mn+1 2 (1) Funktionen f0; f1; f2; : : : Bemerkung: Formaler Beleg fur die intuitiv logische Erkenntnis, da die Wahrscheinlichkeit fur Kollisionen (und damit die durchschnittliche Laufzeit) mit wachsendem Verhaltnis m=n nur kleiner wird. Erinnerung: { 0; : : : ; m ; 1 Indexbereich der Arrays. { n m Anzahl der gespeicherten Elemente. Informatik II { Sommersemester 1999 367 Informatik II { Sommersemester 1999 368 Notation fur den Beweis von Teilbehauptung I: pi: Wahrscheinlichkeit, da genau i Auswertungen notig sind (i 2 f1; : : : ; mg). ;! Durchschnittliche Anzahl Auswertungen ist n X i=1 i=1 qi = p1 + p2 + p3 + p4 + + p2 + p3 + p4 + + p3 + p4 + + p4 + i pi : qi: Wahrscheinlichkeit, da mindestens i Auswertungen notig sind. + + + + n X n X i=1 j =i pi pi pi pi = n X i=1 ;! 369 Ansatz: pj = + + + + + pn-1 + pn + pn-1 + pn + p n-1 + pn + p n-1 + pn + pi + + p n-1 + pn + pn-1 + pn i -mal ;! qi = pi + pi+1 + + pn. Informatik II { Sommersemester 1999 n X Beachte: + pn i pi : n X i=1 qi 2 (1) zu beweisen. Informatik II { Sommersemester 1999 370 Allgemein: q1 = 1 ist oensichtlich. Mindestens zwei Auswertungen notwendig. () theKeys[f0(x)] != x und n X i=1 f0(x)] != null. () theKeys[f0(x)] ist eines der n ; 1 momentan gespeicherten Elemente 6= x von insgesamt m theKeys[ Indizes im Hash. ;! q2 = n ; 1 qi = n n;1 n;2 X n;i+1 m;1 m;i+2 i=1 m = n iY ;1 n ; j X i=1 j =1 m;j+1 Nebenrechnung: Fur a < b und c 0 gilt m Mindestens drei Auswertungen notwendig. () theKeys[f0(x)] ist eines der n ; 1 Elemente = 6 x von insgesamt m Indizes, und theKeys[f1 (x)] ist eines der n ; 2 Elemente = 6 x von den restlichen m ; 1. ;! q3 = n m; 1 mn ;; 21 a;c a b;c b wegen (a ; c) b = a b ; c b a b ; c a = (b ; c) a. Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 371 372 Teilbehauptung II: Erfolglose Suche erfordert im Durchschnitt die Auswertung von 1 2 (1) 1 ; mn+1 +1 Funktionen f0; f1; f2; : : : Anwendung der Nebenrechnung: n iY ;1 n ; j X i=1 j =1 ! m;j+1 n n i ; 1 X i=1 m+1 = nX ;1 i=0 n m+1 i Beweis: q1 = 1 bleibt naturlich. Gesuchter Schlusselwert x ist momentan nicht ge- (Geometrische Reihe:) 1 n i X m+1 i=0 speichert: ;! k Auswertungen sind genau dann notwendig, wenn theKeys[f0 (x)] ... theKeys[fk;2 (x)] != null ist. Konsequenz: n n ; 1 n ; k + 1 qk = m m;1 m;k+1 1 = 1; n m+1 ;! Teilbehauptung I bewiesen. Weiterer Beweis: vollig analog. Informatik II { Sommersemester 1999 373 Typische Wahl der Funktionen f0; f1; f2; : : : Informatik II { Sommersemester 1999 Einschrankung im folgenden zunachst: Schlusselwerte sind naturliche Zahlen. Praktische Einschrankung: Alle Funktionen sollten nach einer einfachen Regel deniert sein. Praktisch bewahrte Ideen fur Funktion f : Grundidee in der Praxis: f (x) := a x + b mit zwei festen Parametern a; b 2 N . Erfahrungsgema gute Streuung fur f0, wenn a, b und m paarweise verschiedene Primzahlen sind. Zwei Funktionen f und g mit Wertebereich N . Fur jeden moglichen Schlusselwert x und jedes i 2 f0; : : : ; n ; 1g wird gesetzt: fi(x) := (f (x) + i g(x)) mod m. Informatik II { Sommersemester 1999 374 f (x) := dm x ze mit einem festen Parameter z 2 (0; 1). Erfahrungsgema gute Streuungpfur f0, wenn z ungefahr der "Goldene Schnitt\ ( 5 ; 1)=2 ist. (Fur diese Erfahrung gibt es sogar mathematische Evidenz, wird hier aber nicht behandelt.) 375 Informatik II { Sommersemester 1999 376 Erinnerung: Andere Arten von Schlusselwerten te f0(x); f1(x); : : : ; fm;1(x) paarweise verschieden sein. Wir hatten uns auf einen Spezialfall "eingeschossen\: fi(x) = (f (x) + i g(x)) mod m. Beispiel: Strings Ideen fur Funktion g: Seien c0(S ); : : : ; c`(S);1(S ) die einzelnen Zeichen Fur jeden Schlusselwert X sollen die Indexwer- von ci. Hashfunktion f : Double Hashing: g wird ahnlich wie f deniert (aber mit anderen Parameterwerten). Erfahrung: Streuverhalten kommt dem Ideal einer rein zufalligen Streuung sehr nah. 377 Warum Primzahlen: Je "primer\ die Parameter pi, um so starker wird erfahrungsgem a jedwede Besonderheit im Datenprol "zerhackt\. Achtung: f (S ) kann sehr schnell Wertebereich von oder sogar long uberschreiten. Technischer Trick: Zwischendurch immer wieder einmal das momentane Zwischenresultat durch Modulobildung mit einer Primzahl q auf sichere Groenordnungen reduzieren. int hashKey = 0; for ( int i=0; i<S.length; i++ ) { int indexOfPrimeNumber = i % r; hashKey += int(S[i]) * p[indexOfPrimeNumber]; if ( hashKey > maxSafeNumber ) hashKey %= q; } Informatik II { Sommersemester 1999 Primzahlen. Fur i 2 f0; : : : ; `(S ) ; 1g sei ai 2 N der ASCII{Wert Keine gute Streuung wegen Haufungsbildungen: f0(x) = f0(y) fur zwei Schlusselwerte x und y ;! fi(x) = fi(y) fur alle i. int Seien p0; : : : ; pr;1 paarweise verschiedene eines Strings S der Lange `(S ). Lineares Sondieren: g(x) = 1 fur alle x. Informatik II { Sommersemester 1999 Idee: 379 f (S ) := `(X S );1 i=0 ai p(i mod r) Analog die Denition der additiven Hashfunktion g (mit anderen Primzahlen). Informatik II { Sommersemester 1999 378 Beispiele fur das Szenario "Statisches Dictionary\, auf das Hash{Tabellen passen: On{Line{Worterbuch: { Schlusselwerte: Die eingetragenen Worter. { Informationen: Die erklarenden Texte. Speicher einer WWW{Suchmaschine: { Schlusselwerte: Alle in den durchsuchten WWW{ Seiten gefundenen Worter. { Informationen: Zu jedem indizierten Wort die Liste der URLs, in denen es gefunden wurde. Informatik II { Sommersemester 1999 380 Merke: Thema 16: Prioritatswarteschlangen Die rein statische Variante von Dictionaries (d.h. nach Aufbau kein Einfugen und Loschen mehr) ist in vielen Anwendungen wichtig. Implementationen von dynamischen Dictionaries wie AVL- und B{Baume garantieren (log n) Aufwand pro Suche und (n log n) fur den Aufbau. Hash{Verfahren konnen im Worst Case nichts Besseres als (n) pro Suche und (n2) fur den Aufbau garantieren. Erfahrungsgema ist der reale Aufwand aber (1) pro Suche und (n) fur den Aufbau. Durch das wilde "Zerhacken\ mittels Primzahlen ist das empirische Laufzeitverhalten im Average Case kaum sensitiv gegenuber dem charakteristischen Datenprol einer konkreten Anwendungssituation. Informatik II { Sommersemester 1999 Wie Dictionaries eine Datenstruktur zum Speicher von Paaren (Schlussel,Information). Aber: Andere Semantik fur Schlussel. { Nicht zum gezielten Suchen eines gegebenen Schlussels, { sondern als Prioritatswert fur die jeweils assozierte Information. 381 Mogliche Realisierung als Java{Interface: public interface PriorityQueue { public Object insert ( Object Object public Object getFirstKey (); public Object getFirstInfo (); public void removeFirst (); public Object getKey ( Object public void changeKey ( Object Object } Informatik II { Sommersemester 1999 382 Weitere Erlauterungen: Methoden getFirstKey bzw. getFirstInfo liefern den Schlussel bzw. die Information desjenigen Paares, das momentan unter allen Paaren den kleinsten Schlusselwert (=die hochste Prioritat) besitzt. key, info ); Bei mehreren Kandidaten mit kleinstem identification ); identification, key ); Erlauterungen: Methode insert fugt ein neues Paar ein und liefert Schlusselwert: { Einer davon wird ausgewahlt. { Die Auswahl ist nicht festgelegt, { sondern kann in jeder Klasse, die das Interface PriorityQueue jeweils implementiert, nach Gu" sto\ sein. eine anonyme Identikation dieses Paares zuruck. Methode getKey liefert fur diese Identikation danach den Schlusselwert dieses Paares zuruck. Methode changeKey uberschreibt den so identizierten Schlusselwert durch Parameter key. Methode removeFirst loscht genau dieses Kandi- Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 383 datenpaar. 384 Beobachtung: Dictionary{Implementationen lassen sich auch zur Realisierung von Priority Queues verwenden. ;! Priority Queues lassen sich mittels AVL{ Baumen so implementieren, da jede Operation (log n) Laufzeit bei n momentan gespeicherten Elementen erfordert. insert: Wie put, nur da der Verweis auf das eingefugte TreeNode{Objekt (Referenzvariable vom Typ TreeNode) als Identikation zuruckgeliefert wird. getKey: Dann trivial. changeKey: Erst loschen, dann mit neuem Schlusselwert wieder einfugen. Achtung: Damit die Identikation nicht falsch wird, mu das neu eingefugte TreeNode{Objekt physisch mit dem "ausgeklinkten\ identisch sein. getFirstKey , getFirstInfo und removeFirst: Der Schlussel des "linkesten\ Elements im ganzen Baum. Informatik II { Sommersemester 1999 385 Begrundung: Mit einer Priority Queue kann man sortieren. Die Laufzeit fur diesen Sortieralgorithmus wird von der Laufzeit fur diese drei Operationen auf der Priority Queue dominiert. Selbst unter der Annahme, da der Vergleich zweier Werte (1) ist, geht Sortieren aber grundsatzlich nicht schneller als (n log n) im Average und Worst Case (Thema 10). Nebenresultat: Dieselbe Argumentation liefert fur Dictionaries das analoge Negativresultat: Besser als (log n) ist in jeder Implementation von Dictionaries fur mindestens eine der Operationen nicht drin. Informatik II { Sommersemester 1999 387 Frage: Es wird nur ein Teil der Funktionalitat von Dictio- naries verwendet. Bei Hash{Tabellen konnte man diesen Tatbestand ausnutzen, um etwas Besseres als (log n) zumindest im Average Case zu bekommen. Kann man das auch bei Priority Queues erreichen? Antwort: Selbst unter der idealisierten Annahme, da jeder Vergleich nur (1) Zeit braucht, braucht in jeder nur moglichen Implementation von Priority Queues mindestens eine der Operationen insert, getFirstKey und removeFirst mindestens (log n) Laufzeit schon im Average Case (erst recht im Worst Case). Informatik II { Sommersemester 1999 386 Sortieren durch Priority Queues Technische Annahmen: Klasse MyPriorityQueue PriorityQueue und implementiert Interface hat einen Konstruktor, der ein Comparator{Objekt als Argument erhalt und intern zum Groenvergleich von Schlusselwerten verwendet. Idee: Die zu sortierenden Elemente sind die Suchschlussel (und die Information ist irrelevant und daher einfach null). public void sort ( Object[] A, Comparator cmp ) { MyPriorityQueue queue = new MyPriorityQueue (cmp); for ( int i=0; i<A.length; i++ ) queue.insert ( A[i], null ); for ( int i=0; i<A.length; i++ ) { A[i] = queue.getFirstKey(); queue.removeFirst(); } } Informatik II { Sommersemester 1999 388 Frage: Ist damit das Thema Priority Queues nicht erledigt? Konkrete Konsistenzbedingungen: Antwort: Man kann immer noch etwas an den Pro- m + 1 Komponenten. Die n momentan gespeicherten Elemente nden sich an den Indizes 1; : : : ; n. Heapeigenschaft: Fur alle i > 1 gilt portionalitatsfaktoren und an der Kompliziertheit der Datenstruktur verbessern. Ergebnis wird sein: Eine Datenstruktur namens Heap. Einschrankung: Es wird vorausgesetzt, da eine obere Schranke m fur die Anzahl zu speichernder Elemente bekannt ist. ;! Wird als weiteres Konstruktorargument vorab ubergeben. Im wesentlichen implementiert als Arrays theKeys und theInfos. Ein "Mittelding\ zwischen sortiertem und unsortiertem Array. Informatik II { Sommersemester 1999 389 Array theKeys und theInfos i A[ ]>=A[ Frage: Warum wird Index 0 ausgelassen? Antwort: Allein aus notationellen Grunden, namlich zur Vereinfachung der Formulierung der Heapeigenschaft. Informatik II { Sommersemester 1999 390 Die besetzten Arrayindizes 1; : : : ; n werden Schicht fur Schicht von links nach rechts den Baumknoten zugeordnet. Fur i > 1 ist Index bi=2c dann der unmittelbare Vorganger von Index i im Baum. ;! Teilweise Sortierung des Arrays theKeys (namlich entlang jedes Baumpfades). theKeys[2] theKeys[8] theKeys[9] Informatik II { Sommersemester 1999 theKeys[11] 125 178 141 475 141 255 143 222 144 876 365 597 401 An der Wurzel steht immer ein Element mit kleinsten Schlusselwert. ;! (1) Laufzeit fur getFirstKey und getFirstInfo. Der Baum ist vollstandig balanciert und hat (wie jeder vollstandig balancierte Baum) ungefahr doppelt so viele Knoten wie Blatter (vgl. Thema 13). ;! Hohe 2 (log n) (vgl. Thema 10). theKeys[3] theKeys[10] 125 Beobachtungen: theKeys[1] theKeys[5] bi=2c]. Zahlenbeispiel fur theKeys: Intuition: als Baumstruktur theKeys[4] haben mindestens theKeys[6] theKeys[12] theKeys[7] theKeys[13] theKeys[14] 391 Informatik II { Sommersemester 1999 392 Nachstes Ziel: Methode Laufzeit. changeKey mit (log n) Beispiel fur Hochtauschen: 876 ;! 150 Ausgangssituation: 125 Idee: Das Element mit verandertem Schlusselwert wird im Heap Schritt fur Schritt hochgetauscht, falls der Schlusselwert verringert wurde und hinabgetauscht, falls der Schlusselwert erhoht wurde. Abbruch: Sobald die Heapeigenschaft nicht mehr ver- 125 178 141 475 141 255 143 222 144 125 178 141 475 1. Austauschschritt: 141 255 143 222 144 178 143 394 150 144 222 365 597 150 125 141 401 475 ;! Verletzung der Heapeigenschaft ist um eine 255 178 141 143 144 222 365 597 401 ;! Keine Verletzung der Heapeigenschaft mehr. ;! Fertig mit Hochtauschen. Stufe nach oben getauscht worden. Informatik II { Sommersemester 1999 401 125 141 255 597 2. Austauschschritt: 125 475 150 365 Informatik II { Sommersemester 1999 125 141 401 125 Feinheit: Beim Hinabtauschen stehen im allgemeinen zwei Nachfolger als Kandidaten zum Austausch zur Verfugung. ;! Immer den kleineren von beiden nehmen. 393 597 Schlusselwert verringert: letzt ist. Informatik II { Sommersemester 1999 876 365 395 Informatik II { Sommersemester 1999 396 Beispiel fur Herabtauschen: 178 ;! 999 Ausgangssituation: 1. Austauschschritt: 125 125 125 178 125 141 141 222 222 365 141 475 255 143 144 876 597 141 365 999 401 475 255 143 144 876 597 401 Schlusselwert erhoht: Immer der kleinere Nachfolger gewahlt: 125 125 141 475 141 255 ;! Verletzung der Heapeigenschaft wird nicht du- 999 143 222 144 876 pliziert, sondern ist um eine Stufe nach unten getauscht worden. 365 597 401 Informatik II { Sommersemester 1999 397 2. Austauschschritt: 398 Methode removeFirst: Erinnerung: Die gespeicherten Elemente belegen die Arrayindizes 1; : : : ; n. 125 125 141 Informatik II { Sommersemester 1999 ;! Implementation eines Heaps braucht zur Iden- tikation der belegten Indizes also nur eine zusatzliche Objektvariable n. 222 141 365 597 Idee fur removeFirst: 475 255 143 144 876 999 401 Vertausche theKeys[1] mit theKeys[n] und theInfos[1] ;! Keine Verletzung der Heapeigenschaft mehr. ;! Fertig mit Hinabtauschen. mit theInfos[n]. Setze n = n-1. Problem: theKeys[1] ist nun potentiell groer als oder theKeys[3] und verletzt somit die Heapeigenschaft. ;! Einfach wieder hinabtauschen. theKeys[2] Informatik II { Sommersemester 1999 399 Informatik II { Sommersemester 1999 400 Methode insert: Setze n = n+1 und fuge das neue Element am neuen Index n ein. Weiteres Problem: ;! Potentiell ist nun theKeys[n]<theKeys[bi=2c]. ;! Einfach wieder hochtauschen. Durch Oen: Identikation von Elementen fur Wie ndet man ezient eine freie Komponente? changeKey. getKey und Problem: Der Index eines Elements in theKeys und andert sich und taugt daher nicht zur Identikation von auerhalb des Heaps. theInfos Losung: Zusatzarray theIndexes mit gleich viel Elementen removeFirst freigewordene Komponenten in theIndexes mussen bei spateren insert's "recycelt\ werden. Losung: Freie Komponenten sind in einer Zusatzliste theFreeSlots untereinander verbunden. wie theKeys und theInfos. Je ein Eintrag mit festem Index fur jedes momentan gespeicherte Element. Inhalt: Momentaner Index des Elements in theKeys und theInfos. Einfugen einer freigewordenen Komponenten und Informatik II { Sommersemester 1999 Informatik II { Sommersemester 1999 401 Intuition: Herausnahme zur Wiederverwendung immer am Anfang der Liste (;! (1)). 402 Merke: Priority Queues lassen sich als Spezialisierung 1 von Dictionaries interpretieren. 4 6 5 9 8 Implementationen von Priority Queues (und 3 2 10 11 12 erst recht Dictionaries) konnen grundsatzlich nichts Besseres als (log n) im Average und Worst Case fur die wesentlichen Methoden erreichen. 7 13 14 Die Realisierung als Heap erreicht dies mit 12 2 6 3 9 0 11 7 0 8 10 4 13 0 14 0 1 5 0 0 recht kleinen Proportionalitatsfaktoren. 0 Bemerkung: Sortieren auf Basis von Heaps theFreeSlots Informatik II { Sommersemester 1999 ist in der Literatur als Heapsort bekannt. null 403 Informatik II { Sommersemester 1999 404 Netzwerk: Thema 17: Kurzeste Wege in Netzwerken Offenburg Ulm Kontext: Der Algorithmus von Dijkstra ist eine gute Beispielanwendung fur Heaps. Gegeben: Freiburg { Ein Netzwerk bestehend aus n Knoten und m Kanten, { eine positive Lange fur jede Kante sowie { ein Start- und ein Zielknoten. Lindau Winterthur Implementation von Netzwerken mit (n + m) Speicherplatz: Ein Array von Knoten. Zu jedem Knoten ein Array von hinauszeigenden Kanten. Zu jeder Kante wird der Index ihres unmittelbaren Zielknotens gespeichert. Informatik II { Sommersemester 1999 405 Informatik II { Sommersemester 1999 406 Notation: Intuition zur Implementation: Informatik II { Sommersemester 1999 Meersburg Friedrichshafen Singen Zürich ;! Vergleiche Ende von Thema 2. 13 14 15 16 Stockach TitiseeNeustadt Basel Ein kurzester Pfad im Netzwerk vom Start- zum Zielknoten. Ulm : Villingen-Schwenningen : Winterthur : Zürich : Biberach Donaueschingen Konstanz Gesucht: Basel : 0 Biberach : 1 Donaueschingen : 2 Freiburg : 3 Friedrichshafen : 4 Konstanz : 5 Lindau : 6 Meersburg : 7 Offenburg : 8 Riedlingen : 9 Singen : 10 Stockach : 11 Titisee-Neustadt : 12 Riedlingen VillingenSchwenningen 3 9 10 0 6 10 4 4 3 1 2 7 2 9 2 10 0 Eine Kante von u nach v wird mit (u; v) bezeichnet. `(u; v) > 0 ist die Lange einer Kante (u; v), und 16 `(p) die Lange eines Pfades p. Startknoten s, Zielknoten t. Fur einen Knoten v sei s(v) die Lange eines kurzesten Pfades von s nach v. 12 14 8 12 7 Beobachtung: Es endet genau dann ein kurzester (s; v){Pfad mit der Kante (u; v), wenn `(u; v) = s(v) ; s(u) ist. Beweis: 11 14 11 13 5 11 15 9 10 3 s p u v Sei p ein kurzester (s; u){Pfad. ;! `(p) = s(u) ;! s(v) = `|(p)+{z`(u; v}) () `(u; v) = s(v) ; s(u) Lange des Pfades "p + (u; v)\. 8 16 15 407 Informatik II { Sommersemester 1999 408 Konsequenz: Falls der Wert s(v) fur jeden Knoten v bekannt ist, lat sich ein kurzester (s; t){Pfad von t aus ruckwarts nach s konstruieren: 1. Starte mit i := 1, v1 := t und Pfad p := ;. 2. Solange vi 6= s, wiederhole: (a) Suche eine Kante (vi+1; vi) mit `(vi+1; vi) = (vi) ; (vi+1). (b) Fuge (vi+1; vi) vorne an p an. (c) Setze i := i + 1. s=vk vk-1 ;! `(p) = kX ;1 i=1 vk-2 v4 v3 v2 Technische Feinheit: Fur diese Ruckwartsberechnung eines kurzesten Pfades aus den {Werten braucht man eine umgekehrte Verzeigerung (d.h. jede Kante halt einen Verweis auf ihren Ursprungsknoten). Knotenbewertung berechnen: Der eigentliche Algorithmus von Dijkstra Basis: Reellwertige Variable (v) fur jeden Knoten v. t=v1 (s(vi) ; s(vi+1)) = s(v1) ; s(vk) = s(t) Informatik II { Sommersemester 1999 409 Schleifeninvarianten nach i Durchlaufen: (s) = 0 (anders gesagt: (s) = (s)). (v) (v) fur alle Knoten s 6= v. Informatik II { Sommersemester 1999 410 Intuition fur die Wellenfront: Es gibt eine Partition der Knoten in { eine momentane "Wellenfront\ Wi, { die Menge Si aller Knoten, uber die die Wellen- front schon hinweggegangen ist, { und die Restmenge Xi. Die Menge Si besteht genau aus s und den i Knoten v 6= s mit kleinsten Werten (v). Wi besteht genau aus den Knoten v 62 Si, zu denen eine Kante aus Si hinzeigt. Fur jeden Knoten v 2 Si [ Wi ist (v) die Lange eines kurzesten (s; v){Pfades, der (ggf. abgesehen von v selbst) nur Knoten aus Si enthalt. ;! Am Ende, wenn die Wellenfront uber alle Knoten hinweggegangen ist, gilt . Informatik II { Sommersemester 1999 411 111111111111111111 000000000000000000 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 s 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 Informatik II { Sommersemester 1999 412 Initialisierung: Kernschleife: (s) := 0. Fur jeden Knoten v mit Kante (s; v) wird gesetzt Si entsteht aus Si;1 durch Einfugen des Knotens v 2 Wi;1 mit minimalem momentanem Wert (v). Fur jeden weiteren Knoten v wird (v) auf einen Wi entsteht aus Wi;1, indem dieser Knoten v aus (v) := `(s; v). Wert gesetzt, der von der Implementation im weiteren als "1\ interpretiert wird, zum Beispiel { ein unmoglich groer Wert, { ein negativer und damit ganzlich unmoglicher Wert. Wi;1 entfernt wird und alle Knoten w 62 (Si;1 [ Wi;1), fur die es eine Kante (v; w) gibt, eingefugt werden. Dabei wird jeweils gesetzt: (w) := minf(w); (v) + `(v; w)g. Konsequenz: S0 = fsg. W0 besteht aus allen Knoten, zu denen eine Kante von s aus unmittelbar hinzeigt. Informatik II { Sommersemester 1999 413 Korrektheit der Schleifeninvariante mit vollstandiger Induktion: Informatik II { Sommersemester 1999 414 Intuition zum Induktionsschritt: Induktionsanfang: Ergibt sich sofort aus der Initialisierung. Induktionsschritt: Alle Kantenlangen sind nichtnegativ. ;! Wenn ein Pfad teilweise uber Knoten auerhalb von Wi;1 [ Si;1 verlauft, kann er dadurch nur langer werden. ;! Fur den Knoten v 2 Wi;1 mit mini- malem s(v) geht der kurzeste Pfad ganz durch Si;1 [ Wi;1. 111111111111111111 000000000000000000 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 s 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 000000000000000000 111111111111111111 Aber: Nach Induktionsvoraussetzung ist die kurzeste Lange eines solchen Pfades gerade (v). Informatik II { Sommersemester 1999 415 Informatik II { Sommersemester 1999 416 Laufzeit Wellenfront Wi ist Inhalt einer Priority Queue: { Information: Knoten v. { Schlusselwert: (v). Si wird uberhaupt nicht explizit verwaltet (wozu Merke: Semester ist zu Ende! auch?). Die Groe der Priority Queue ist durchgangig beschrankt durch die Gesamtzahl n von Knoten im Netzwerk. Jeder Knoten wird nur einmal in Wi eingefugt (also auch nur einmal geloscht). ;! (n log n) fur alle insert's und removeFirst's zusammen. Jede der m Kanten im Netzwerk kann genau einmal eine Reduzierung eines Wertes (v) provozieren. ;! (m log n) fur alle getKey's und changeKey's zusammen. Zusammengefat: ((n + m) log n) Informatik II { Sommersemester 1999 417 Informatik II { Sommersemester 1999 418