Wiederholung ADT Menge: I Sorten: Bool, Element, MengehElementi I Signatur: isempty : Menge → emptyset : add : Menge × Element → remove : Menge × Element → contains : Menge × Element → Bool Menge Menge Menge Bool Datenstrukturen zur Implementierung: meist zum Speichern von Paaren (Schlüssel, Wert) I Liste mit n Knoten (evtl. sortiert, einfach oder doppelt verkettet): Laufzeit contains: zwischen O(log n) und O(n) Laufzeit add, remove: zwischen O(1) und O(n) I Suchbäume t (evtl. balanciert) mit n Knoten: Laufzeit contains, add, remove: O(tiefe(t)), zwischen O(log n) (balanciert) und O(n) 164 Hashing Speichern von Paaren (Wert, Adresse) Menge aller Werte: D Hashtabelle (Speicher): m Behälter (Buckets) meist m viel größer als |D| Menge aller Adressen: {0, . . . , m − 1} Idee: Berechnung eines Behälter-Index (Adresse) durch eine Hashfunktion H : D → {0, . . . , m − 1} Zugriff auf Wert v über Adresse h(v ) 165 Hashfunktion erwünschte Eigenschaften: I effizient berechenbar O(1) I surjektiv (jede Adresse als Funktionswert eines Wertes) I möglichst gleichmäßige Verteilung der Werte auf den Adressbereich Beispiel: 7 Wochentage (zwei Anfangsbuchstaben) mit 10 Adressen: h(v ) = (Index des Anfangsbuchstaben) mod 10 0 1 2 3 4 5 6 7 8 9 Mo, Mi Di, Do Fr Sa, So h0 (v ) = (Summe der Buchstabenindizes) mod 10 0 1 2 3 4 5 6 7 8 9 SA MI DI FR,SO MO DO übliche Hashfunktionen: h(v ) = v mod m, h(v ) = mittlere Ziffern von v 2 166 Kollisionen Kollision: Werte u 6= v mit h(u) = h(v ) Kollisionen kommen relativ häufig vor. Geburtstagsparadoxon: Unter 23 Personen haben mit 50% Wahrscheinlichkeit zwei denselben Geburtstag. Kollisionsbehandlung: offenes Hashing: Speichern mehrerer Werte in einem Behälter (z.B. Liste) geeignet bei häufigem Einfügen und Löschen geschlossenes Hashing: systematische Berechnung neuer Adressen bei belegtem Behälter geeignet bei bekannter Anzahl zu speichernder Werte (günstig bis 80% belegten Behältern) 167 Offenes Hashing (seperate chaining) Behälter: Liste (einfach oder doppelt verkettet) Hashtabelle: Array fester Länge m von Listen Operationen: Suche eines Wertes v : Suche in der Liste mit Adresse h(v ) Löschen eines Wertes v : Löschen aus der Liste mit Adresse h(v ) Einfügen eines Wertes v : Einfügen in die Liste mit Adresse h(v ) Länge der Listen bei m Behältern und n Werten durchschnittlich n/m. Durchschnittliche Laufzeit von Suche, Einfügen, Löschen (für n ≈ m): O(1 + n/m) = O(1) worst case: alle Werte in einer Liste Laufzeit von Suche, Einfügen, Löschen: O(n) 168 Geschlossenes Hashing I I Behälter: Speicher für genau einen Wert zwei zusätzliche Werte: frei, gelöscht Hashtabelle: Array fester Länge m von Werten Idee: I Jedem Wert v wird ein Sondierungspfad s(v ) = (s0 (v ), s1 (v ), . . .) (Liste von Adressen) zugeordnet. I Zum Speichern von v wird s(v ) bis zur ersten freien Adresse si (v ) durchlaufen. Invariante für Hashtabelle T : 1. T enthält wenigstens einen leeren Behälter. 2. Für Sondierungspfad s(v ) eines Elementes v gilt: Ist v in T enthalten, dann I I steht v an einer Position si (v ) des Sondierungspfades s(v ) = (s0 (v ), . . . , sn (v )) und alle Positionen j < i auf dem Sondierungspfad s(v ) sind nicht frei. 169 Operationen bei geschlossenem Hashing Suchen, Löschen, Einfügen eines Wertes v in Hashtabelle T : Durchlauf des Sondierungspfades s(v ) I Suche eines Wertes v in T : I I I v ist genau dann in T enthalten, falls v an einer Adresse des Sondierungspfades s(v ) gespeichert ist. Durchlauf des Sondierungspfades genügt nach Invariante. Suche erfolgreich, falls v auf s(v ) gefunden. Suche erfolglos, falls erste freie Adresse auf s(v ) gefunden. I Einfügen eines Wertes v in T : an der ersten Adresse mit Wert „frei“ oder „gelöscht“ auf dem Sondierungspfad s(v ) I Löschen eines Wertes v aus T : Suche nach dem Wert v auf dem Sondierungspfad s(v ), falls v gefunden, mit Wert „gelöscht“ überschreiben Warum? 170 Wahl der Sondierungsfunktion N Sondierungsfunktion s : × D → {0, . . . , m − 1} zu Berechnung des Sondierungspfades für einen Wert v s(v ) = (s0 (v ), s1 (v ), . . .) erwünschte Eigenschaften: I effizient zu berechnen, I für jeden Wert v überdeckt der Sondierungspfad s alle Behälter I möglichst gleichmäßige Verteilung der Werte über die Hashtabelle (Cluster vermeiden) übliche Verfahren: lineares Sondieren: si = (h(v ) + i) mod m Modifikation si = (h(v ) + ci) mod m quadratisches Sondieren: si = (h(v ) + i 2 ) mod m doppeltes Hashing: si = (h(v ) + ih0 (x)) mod m mit zweiter Hashfunktion h0 171 Lineares Sondieren Sondierungsfunktionen si (v ) = (h(v ) + i) mod m Beispiel: m = 13, h(v ) = v mod 13 Einfügen von 18, 41, 22, 44, 59, 32, 31, 73 I Vorteile: schnell, einfach I Nachteile: Clusterbildung Verallgemeinerung: Hashfunktionen si (v ) = (h(v ) + ci) mod m 172 Quadratisches Sondieren Sondierungsfunktionen si (v ) = (h(v ) + i 2 ) mod m Beispiel: m = 13, h(v ) = v mod 13 Einfügen von 18, 41, 22, 44, 59, 32, 31, 73 I Vorteile: vermeidet Clusterbildung I Nachteile: Sondierungsfolge nur halb so lang wie Hashtabelle I überdeckt für Primzahl-Modul Verallgemeinerung: Hashfunktionen s2i−1 (v ) = (h(v ) + i 2 ) mod m s2i (v ) = (h(v ) − i 2 + m2 ) mod m 173 Doppeltes Hashing voneinander unabhängige Hashfunktionen h, h0 definieren die Folge von Positionen: si (v ) = (h(v ) + ih0 (v )) mod m Beispiel: m = 13 h(v ) = v mod 13 h0 (v ) = 7 − (v mod 7) Einfügen von 18, 41, 22, 44, 59, 32, 31, 73 lineares Hashing ist ein einfacher Spezialfall mit h0 (v ) = . . . 174 Laufzeit der Operationen Worst-Case für alle Hashverfahren für Suche, Einfügen, Löschen: O(n) Average-Case für gute Hashverfahren für Suche, Einfügen, Löschen: O(1) 175 Dynamische Hashtabellen Problem: zuvor festgelegte der Größe der Hashtabelle kann sich später als ungeeignet (zu klein oder groß) erweisen Idee: dynamische Anpassung der Größe der Hashtabelle Rehashing (häufig bei zu über 80% gefüllten Hashtabellen): 1. Festlegung I I der neuen Größe und einer neuen Hashfunktion 2. Übertragung (Einfügen) aller Werte in die neue Hashtabelle 176 Zusammenfassung Datenstrukturen für Mengen I lineare Datenstrukturen: I I I Folgen (evtl. sortiert): Arrays, Listen (einfach, doppelt verkettet) Hashtabellen hierarchische Datenstrukturen: I I I binäre Suchbäume binäre Suchbäume mit Balance-Eigenschaft, z.B. AVL-Bäume, Rot-Schwarz-Bäume balancierte Mehrweg-Suchbäume, z.B. B-Bäume 177