Datenstrukturen Mariano Zelke Sommersemester 2012 Prioritätswarteschlangen: Zusammenfassung (a) Ein Heap mit n Prioritäten unterstützt jede der Operationen insert, delete max, change priority und remove in Zeit O(log2 n). I Für die Operationen change priority und remove muss die Position der zu ändernden Priorität bekannt sein. (b) build heap baut einen Heap mit n Prioritäten in Zeit O(n). (c) heapsort sortiert n Zahlen in Zeit O(n log2 n). Mariano Zelke Datenstrukturen 2/29 Das Single-Source-Shortest-Path-Problem Ein gerichteter Graph G = (V , E ) und eine Längen-Zuweisung länge: E → R≥0 an die Kanten des Graphen ist gegeben. Bestimme kürzeste Wege von einem ausgezeichneten Startknoten s ∈ V zu allen Knoten von G . I Die Länge eines Weges ist die Summe seiner Kantengewichte. I Mit Hilfe der Breitensuche können wir kürzeste-Wege Probleme lösen, falls länge(e) = 1 für jede Kante e ∈ E gilt. Für allgemeine nicht-negative Längen brauchen wir eine ausgeklügeltere Idee. I I Mariano Zelke Kantengewichte sind nicht-negativ: Die kürzeste, mit s verbundene Kante (s, v ) ist ein kürzester Weg von s nach v . Dijkstras Algorithmus setzt diese Beobachtung wiederholt ein. Datenstrukturen 3/29 Dijkstras Algorithmus (1) Setze S = {s} und für alle Knoten v ∈ V \ {s} setze länge (s, v ) wenn (s, v ) ∈ E distanz[v] = ∞ sonst. /* distanz[v] ist die Länge des bisher festgestellten kürzesten Weges von s nach v . */ (2) Solange S 6= V wiederhole (a) wähle einen Knoten w ∈ V \ S mit kleinstem Distanz-Wert. /* distanz[w] ist die tatsächliche Länge eines kürzesten Weges von s nach w . */ (b) Füge w in S ein. (c) Aktualisiere die Distanz-Werte der Nachfolger von w : Setze für jeden Nachfolger u ∈ V \ S von w distanz[u] = min(distanz[u], distanz[w]+länge(w,u)); Mariano Zelke Datenstrukturen 4/29 Datenstrukturen für Dijkstras Algorithmus In der Vorlesung Algorithmentheorie“ wird gezeigt, dass Dijkstras ” Algorithmus korrekt ist und das Kürzeste-Wege-Problem effizient löst. I I Darstellung des Graphen G : Wir implementieren G als Adjazenzliste, da wir dann sofortigen Zugriff auf die Nachfolger u von w im Aktualisierungschritt (2c) haben. Implementierung der Menge V \ S: I I Knoten sind gemäß ihrem anfänglichen Distanzwert einzufügen. Ein Knoten w mit kleinstem Distanzwert ist zu bestimmen und zu entfernen. Wähle einen Min-Heap, um die entsprechende Prioritätswarteschlange zu implementieren: I I Mariano Zelke Ersetze die Funktion delete max() durch die Funktion delete min(). (Und passe repair up und repair down entsprechend an.) Implementiere den Aktualisierungschritt (2c) durch change priority(wo,neue Distanz). Woher kennen wir die Position wo? Datenstrukturen 5/29 Minimale Spannbäume (Link) Sei G = (V , E ) ein ungerichteter, zusammenhängender Graph. Jede Kante e ∈ E erhält eine positiv, reellwertige Länge länge(e)“. ” I Ein Baum T = (V 0 , E 0 ) heißt ein Spannbaum für G , falls V 0 = V und E 0 ⊆ E . I Die Länge eines Spannbaums ist die Summe der Längen seiner Kanten. I Ein minimaler Spannbaum ist ein Spannbaum minimaler Länge. I Je zwei Knoten von G bleiben auch in einem Spannbaum T miteinander verbunden, denn ein Baum ist zusammenhängend. Wenn wir aber irgendeine Kante aus T entfernen, dann zerstören wir den Zusammenhang. I Wir suchen nach einem zusammenhängenden Teilgraph in G , der minimale Länge hat. Mariano Zelke Datenstrukturen 6/29 Der Algorithmus von Prim (1) Setze S = {0}. /* B ist stets ein Baum mit Knotenmenge S. Zu Anfang besteht B nur aus dem Knoten 0. */ (2) Solange S 6= V , wiederhole: (a) Bestimme eine kürzeste kreuzende Kante e = {u, v }. (b) Füge e zu B hinzu. (c) Wenn u ∈ S, dann füge v zu S hinzu. Ansonsten füge u zu S hinzu. /* Beachte, dass wir neue kreuzende Kanten erhalten, nämlich alle Kanten die den neu hinzugefügten Knoten als einen Endpunkt und einen Knoten aus V \ S als den anderen Endpunkt besitzen. */ Mariano Zelke Datenstrukturen 7/29 Die Datenstrukturen für Prims Algorithmus I I Für jeden Knoten u ∈ V \ S bestimmen wir die Länge l(u) einer kürzesten Kante, die u mit einem Knoten in S verbindet. Wir verwalten die Knoten in V \ S mit einer Prioritätswarteschlange und definieren l(u) als die Priorität des Knotens u. I I I I Initialisiere einen Min-Heap, indem jeder Nachbar u von Startknoten 0 mit Priorität länge({0, u}) einfügt wird, bzw. mit Priorität ∞, wenn u kein Nachbar ist. Wir bestimmen also eine kürzeste kreuzende Kante, wenn wir einen Knoten in u ∈ V \ S mit niedrigster Priorität bestimmen. Beachte, dass sich nur die Prioritäten der Nachbarn von u ändern. Implementiere G durch eine Adjazenzliste, da wir stets nur auf die Nachbarn eines Knoten zugreifen müssen. Mariano Zelke Datenstrukturen 8/29 Kruskals Algorithmus: Die Idee I I Prims Algorithmus lässt einen minimalen Spannbaum Kante für ” Kante“ wachsen. Kruskals Algorithmus beginnt mit einem Wald von Einzelknoten. I I I Mariano Zelke Die Kanten werden nach aufsteigender Länge sortiert und der Reihe nach, beginnend mit Kanten kürzester Länge verarbeitet. Wenn die Kante e an der Reihe ist und keinen Kreis schließt, dann wird die Kante e zum Wald hinzugefügt. Ansonsten schließt die Kante e einen Kreis und wird verworfen. Datenstrukturen 9/29 Kruskals Algorithmus (1) Sortiere die Kanten gemäß aufsteigender Länge. Sei W = (V , F ) der leere Wald, also F = ∅. (2) Solange W kein Spannbaum ist, wiederhole (a) Nimm die gegenwärtig kürzeste Kante e und entferne sie aus der sortierten Folge. (b) Verwirf e, wenn e einen Kreis in W schließt. (c) Ansonsten setze F = F ∪ {e}: e wird zum Wald W hinzugefügt. Wir beschränken uns auf die Implementierung. In der Vorlesung Algorithmentheorie“ wird gezeigt, dass Kruskals ” Algorithmus korrekt ist. Mariano Zelke Datenstrukturen 10/29 Beispiel Kruskals Algorithmus Hamburg Rostock Bremen Oldenburg 2 9 39 16 12 11 21 18 Berlin Hannover 6 7 Dortmund 19 16 Leipzig 8 17 10 Frankfurt/M. 14 12 Karlsruhe Mariano Zelke Dresden Datenstrukturen Nürnberg 15 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg 16 8 39 10 6 15 17 12 3 14 9 11 12 2 16 21 19 7 18 Rostock Bremen Oldenburg Berlin Hannover Leipzig Dortmund Dresden Frankfurt/M. Nürnberg Karlsruhe München Mariano Zelke Datenstrukturen 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Rostock Bremen Oldenburg Berlin Hannover Leipzig Dortmund Dresden Frankfurt/M. Nürnberg Karlsruhe München Mariano Zelke Datenstrukturen 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Rostock Bremen 2 Oldenburg Berlin Hannover Leipzig Dortmund Dresden Frankfurt/M. Nürnberg Karlsruhe München Mariano Zelke Datenstrukturen 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Mariano Zelke Rostock Bremen 9 Oldenburg 2 11 Berlin Hannover 6 7 Leipzig 8 Dortmund 10 Dresden Frankfurt/M. Nürnberg Karlsruhe Datenstrukturen 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Mariano Zelke Rostock Bremen 9 Oldenburg 2 11 Berlin Hannover 6 7 Leipzig 8 Dortmund 10 Dresden Frankfurt/M. Nürnberg Karlsruhe Datenstrukturen 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Mariano Zelke Rostock Bremen 2 9 Oldenburg 11 12 Berlin Hannover 6 7 Leipzig 8 Dortmund 10 Dresden Frankfurt/M. Nürnberg Karlsruhe Datenstrukturen 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Mariano Zelke Rostock Bremen 9 Oldenburg 2 11 Berlin Hannover 6 7 Leipzig 8 Dortmund 10 Dresden Frankfurt/M. Nürnberg Karlsruhe Datenstrukturen 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Mariano Zelke Rostock Bremen 2 9 Oldenburg 16 11 Berlin Hannover 6 7 Dortmund Leipzig 8 19 10 Frankfurt/M. Dresden 14 12 Karlsruhe Datenstrukturen Nürnberg 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg 2 3 6 7 8 9 10 11 12 12 14 15 16 16 17 18 19 21 39 Mariano Zelke Rostock Bremen 2 9 Oldenburg 16 11 Berlin Hannover 6 7 Leipzig 8 Dortmund 10 Frankfurt/M. Dresden 14 12 Karlsruhe Datenstrukturen Nürnberg 3 München 11/29 Beispiel Kruskals Algorithmus Hamburg Rostock Bremen Oldenburg 2 9 39 16 11 Berlin Aber: Wie stellen wir fest, ob eine Kante einen Kreis schließt? Hannover 6 7 Leipzig 8 Dortmund 10 Frankfurt/M. 14 12 Karlsruhe Mariano Zelke Dresden Datenstrukturen Nürnberg 3 München 11/29 Die Union-Find Datenstruktur I I Wir sortieren die Kanten zum Beispiel mit Heapsort. I Danach müssen wir für jede Kante e = {u, v } entscheiden, ob e einen Kreis in W schließt. I I I Die Operation find(u) bestimme die Wurzel wu des Baumes, der u enthält. Die Kante e schließt genau dann einen Kreis, wenn find(u) = find(v ). Wenn e keinen Kreis in W schließt, dann müssen wir die Bäume mit den Wurzeln find(u) und find(v ) vereinigen. Dazu benutzen wir die Operation union(u, v ). Wie sollten wir den Wald W implementieren? Mariano Zelke Datenstrukturen 12/29 Die Union-Find Datenstruktur II Wir implementieren den Wald W durch ein Vater-Array. I I Zu Anfang ist Vater[i] = i für alle Knoten i. (Wir fassen i immer dann als eine Wurzel auf, wenn Vater[i] = i gilt.) Wie ist find(u) zu implementieren? I I I I Klettere den Baum von u mit Hilfe des Vater-Arrays hoch. Die Kletter-Zeit“ ist durch die Tiefe des Baumes beschränkt. ” Wie garantieren wir, dass die Bäume nicht zu tief werden? Wenn wir zwei Bäume vereinigen, dann hänge die Wurzel des kleineren Baumes unter die Wurzel des größeren Baumes! (Achtung: hierbei wird eine Kante eingefügt, die wir möglicherweise nicht zu W hinzufügen!) I I I Mariano Zelke Betrachte einen beliebigen Knoten v . Die Tiefe vergrößert sich nur dann um 1, wenn v dem kleineren Baum angehört. Wenn die Tiefe von v um 1 anwächst, dann wird sich der Baum von v in seiner Größe mindestens verdoppeln. Also ist die Tiefe aller Bäume durch log2 (|V |) beschränkt. Datenstrukturen 13/29 Die Union-Find Datenstruktur: Das Fazit Ein Union-Schritt benötigt nur konstante Zeit, während ein Find-Schritt höchstens logarithmische Zeit benötigt. I I Mit der Union-Operation modifizieren wir den Wald! Für Kruskals Algorithmus benötigen zwei Datenstrukturen, nämlich I I die Union-Find Datenstruktur und eine zweite Datenstruktur, die die Kanten des minimalen Spannbaums abspeichert. Damit hat Kruskals Algorithmus eine Laufzeit von O(|E | · log |V |) Mariano Zelke Datenstrukturen 14/29 Kapitel 4: Das Wörterbuch Mariano Zelke Datenstrukturen 15/29 Der abstrakte Datentyp Wörterbuch“ ” Ein Wörterbuch für eine gegebene Menge S besteht aus den folgenden Operationen: I insert(x): Füge x zu S hinzu, d.h. setze S = S ∪ {x}. I remove(x): Entferne x aus S, d.h. setze S = S − {x}. I lookup(x): Finde heraus, ob x in liegt, und wenn ja, greife gegebenenfalls auf den Datensatz von x zu. I In einer Firmendatenbank werden Kundendaten in der Form (Kundenummer, Info) abgespeichert. Die Kundennummer stellt den Schlüssel x dar. I I I I Mariano Zelke insert(x): Füge den Datensatz eines neuen Kunden mit Kundenummer x ein. remove(x): Entferne den Datensatz des entsprechenden Kunden. lookup(x): Greife auf den Datensatz des Kunden mit Kundennummer x zu. Datenstrukturen 16/29 Suchmaschinen Suchmaschinen müssen Stichworte und Webseiten verwalten. Insbesondere müssen zu jedem Stichwort alle relevanten Webseiten aufgelistet werden. I Für jedes Stichwort s müssen die relevanten Webseiten schnell verfügbar sein. I Neue Stichworte sind gegebenenfalls einzufügen I Unter einem Stichwort müssen neue Webseiten abgelegt und veraltete gelöscht werden können I Veraltete Stichworte sind zu entfernen Mariano Zelke Datenstrukturen 17/29 Datenstrukturen für Wörterbücher I Wie sollten statische Wörterbücher, also Wörterbücher die nur lookup benutzen, implementiert werden? I I Wir könnten die Menge der n gespeicherten Schlüssel zuerst sortieren. Eine lookup-Operation gelingt dann in logarithmischer Zeit durch binäre Suche. Oder aber wir haben noch mehr Glück und haben eine schnell berechenbare Namensfunktion, die für jeden Schlüssel die Position des Schlüssels bestimmt. Leider sind die interessanten Wörterbücher dynamisch. I Könnten wir Heaps benutzen? Das Einfügen gelingt mühelos, aber schon das Suchen ist extrem mühselig. (Warum?) Wir benötigen eine Datenstruktur, die schnell durchsuchbar und an beliebigen Stellen modifizierbar ist. Mariano Zelke Datenstrukturen 18/29 Binäre Suchbäume T sei ein geordneter binärer Baum. Jeder Knoten v von T speichert ein Paar daten(v ) = (Schlüssel(v ), Info(v )). T heißt binärer Suchbaum, wenn T die folgenden Eigenschaften hat: (a) Für jeden Schlüsselwert x gibt es höchstens einen Knoten v mit Schlüssel (v ) = x. (b) Für jeden Knoten v , jeden Knoten vlinks im linken Teilbaum von v und jeden Knoten vrechts im rechten Teilbaum von v gilt Schlüssel(vlinks ) < Schlüssel(v ) < Schlüssel(vrechts ). Binäre Suchbäume unterstützen die binäre Suche! Mariano Zelke Datenstrukturen 19/29 Operation lookup(x) lookup(x) sucht im Binären Suchbaum folgendermaßen nach dem Knoten mit Schlüssel x: (1) Sei r die Wurzel des binären Suchbaums. Setze v = r . /* Wir beginnen die Suche an der Wurzel. */ (2) Wenn wir am Knoten v angelangt sind, vergleichen wir x mit Schlüssel(v ): I I I x = Schlüssel(v ): Wir haben den Schlüssel gefunden. x < Schlüssel(v ): Wir suchen im linken Teilbaum weiter. x > Schlüssel(v ): Diesmal muss im rechten Teilbaum weitergesucht werden. Lookup benötigt Zeit Θ(t), wobei t die Tiefe des Knoten ist, der den Schlüssel x speichert. Mariano Zelke Datenstrukturen 20/29 Die Struktur Knoten typedef struct Knoten { schluesseltyp schluessel; infotyp info; //Schluesseltyp und Infotyp sind vorspezifizierte Typen, //z.B. int oder string Knoten *links, *rechts; Knoten(schluesseltyp s, infotyp i, Knoten *l, Knoten *r) { schluessel = s; info = i; links = l; rechts = r; } //Konstruktor. }; Mariano Zelke Datenstrukturen 21/29 Die Klasse Binärer Suchbaum class bsbaum{ private: Knoten *Kopf; public: bsbaum( ) { Kopf = new Knoten (0,0,0,0); } // Konstruktor // Kopf->rechts wird stets auf die Wurzel zeigen Knoten *lookup(schluesseltyp x); void insert(schluesseltyp x, infotyp info); void remove(schluesseltyp x); void inorder( ); }; Mariano Zelke Datenstrukturen 22/29 Beispiel binärer Suchbaum *Kopf schluessel: 0 info: 0 *links *rechts schluessel: 11 info: Saturn *links *rechts schluessel: 8 info: Erde *links *rechts schluessel: 3 info: Venus *links *rechts schluessel: 5 info: Jupiter *links *rechts Mariano Zelke schluessel: 17 info: Merkur *links *rechts schluessel: 14 info: Mars *links *rechts schluessel: 12 info: Erde *links *rechts Datenstrukturen schluessel: 19 info: Uranus *links *rechts schluessel: 15 info: Neptun *links *rechts 23/29 Die Funktion lookup Knoten *bsbaum::lookup (schluesseltyp x){ Knoten *Zeiger = Kopf->rechts; while ((Zeiger != 0) && (x != Zeiger->schluessel)){ if ( x < Zeiger->schluessel ) Zeiger = Zeiger->links; else Zeiger = Zeiger->rechts; } return Zeiger; } Mariano Zelke Datenstrukturen 24/29 Beispiel Lookup lookup(52) 52 > 42 42 23 57 52 < 57 12 37 53 62 52 < 53 7 28 41 49 56 61 52 > 49 10 35 44 52 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 25/29 Beispiel Lookup 19 < 42 lookup(19) 42 23 57 19 < 23 12 37 53 62 19 > 12 7 28 10 41 35 49 44 56 52 61 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 25/29 Binäre Suchbäume: Insert Suche zuerst nach x. Sollten wir x finden, überschreibe den alten Info-Teil; sonst füge den Schlüssel dort ein, wo die Suche scheitert. void bsbaum::insert (schluesseltyp x, infotyp info){ Knoten *Vater, *Zeiger; Vater = Kopf; Zeiger = Kopf->rechts; while ((Zeiger != 0) && (x != Zeiger->schluessel)){ Vater = Zeiger; if (x < Zeiger->schluessel) Zeiger = Zeiger->links; else Zeiger = Zeiger->rechts; } if (Zeiger == 0){ Zeiger = new Knoten (x, info, 0, 0); if (x < Vater->schluessel) Vater->links = Zeiger; else Vater->rechts = Zeiger; } else Zeiger->info = info; } Mariano Zelke Datenstrukturen 26/29 Beispiel Insert 52 > 42 42 insert(52,info) 23 57 52 < 57 12 37 53 62 52 < 53 7 28 41 49 56 61 52 > 49 10 35 44 Info-Teil wird 52 mit info 59 überschrieben Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 27/29 Beispiel Insert insert(19,info) 19 < 42 42 23 57 19 < 23 12 37 53 62 19 > 12 7 19 10 28 Neuer Knoten mit Schlüssel 19 und info als Info-Teil wird erzeugt 41 35 49 44 56 52 61 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 27/29 Binäre Suchbäume: Remove Zuerst suche den Schlüssel x. Wenn die Suche im Knoten v endet: I Wenn v ein Blatt ist: Entferne v . I Wenn v genau ein Kind w hat: Entferne v und mache den Vater von v zum Vater von w . Wenn v zwei Kinder hat: Ersetze v durch den kleinsten Schlüssel s im rechten Teilbaum von v . I I I I Mariano Zelke Der Knoten u speichere den Schlüssel s. u ist als linkester Knoten im rechten Teilbaum leicht zu finden. u hat kein linkes Kind und kann damit sofort entfernt werden. Datenstrukturen 28/29 Beispiel Remove 42 remove(56) 23 57 12 7 37 28 10 53 41 35 62 49 44 61 52 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29 Beispiel Remove 42 remove(56) 23 57 12 7 37 28 10 53 41 35 62 49 44 61 52 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29 Beispiel Remove 42 remove(53) 23 57 12 7 37 28 10 62 41 35 49 44 61 52 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29 Beispiel Remove 42 remove(53) 23 57 12 7 37 28 10 49 41 44 35 62 52 61 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29 Beispiel Remove 42 remove(23) 57 12 7 37 28 10 49 41 44 35 62 52 61 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29 Beispiel Remove 42 remove(23) 28 57 12 37 7 49 41 10 44 35 62 52 61 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29 Beispiel Remove 42 remove(23) 28 57 12 7 37 35 49 41 44 10 62 52 61 59 Anmerkung: In diesem Beispiel sind für jeden Knoten im binären Suchbaum nur der Schlüssel schluessel und nicht die Information info dargestellt. Mariano Zelke Datenstrukturen 29/29