Algorithmen und Datenstrukturen

Werbung
Wiederholung
ADT Menge:
I
Sorten: Bool, Element, Menge
I
Signatur:
leer :
Menge →
leeremenge :
add :
Menge × Element →
remove :
Menge × Element →
contains :
Menge × Element →
Bool
Menge
Menge
Menge
Bool
geignete Datenstrukturen:
I
Liste (evtl. sortiert, einfach oder doppelt verkettet)
Laufzeiten O(n)
I
Suchbäume (evtl. balanciert)
Laufzeiten O(log(n))
meist Speichern von Paaren (Schlüssel, Wert)
141
Hashing
Speichern von Paaren (Wert, Adresse)
Menge aller Werte: D
Hashtabelle (Speicher): m Behälter (Buckets)
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 )
142
Hashfunktion
erwünschte Eigenschaften:
I
effizient berechenbar
I
surjektiv (jede Adresse als Funktionswert eines Wertes)
I
möglichst gleichmäßige Verteilung der Werte auf den
Adressbereich
Beispiel: 7 Wochentage (zwei Anfangsbuchstaben) auf 10
Adressen verteilen:
h(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:
I
h(v ) = v mod m
I
h(v ) = mittlere Ziffern von v 2
143
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 denselben Geburtstag.
Kollisionsbehandlung:
offenes Hashing:
Speichern mehrerer Werte in einem Behälter
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% der Arraygröße)
144
Offenes Hashing
(seperate chaining)
Behälter: Liste
Hashtabelle: Array fester Länge m von Listen
Operationen:
Suche eines Wertes v :
Suche in der Liste im Behälter h(v )
Löschen eines Wertes v :
Löschen aus der Liste im Behälter h(v )
Einfügen eines Wertes v :
Einfügen in die Liste im Behälter 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(1 + n) = O(n)
145
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 (Liste von
Adressen) zugeordnet.
I Zum Speichern von v wird s bis zur erste freien Adresse
durchlaufen.
Invariante für Hashtabelle T :
1. T enthält wenigstens einen leeren Behälter.
2. Für Sondierungspfad s eines Elementes v gilt:
Ist v in T enthalten, dann
I
I
steht v an einer Position si des Sondierungspfades von v
und
alle Positionen j < i auf dem Sondierungspfad S sind nicht
frei.
146
Operationen bei geschlossenem Hashing
Suchen, Löschen, Einfügen eines Wertes v in die Hashtabelle
T:
Durchlauf des Sondierungspfades s von 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 gespeichert ist.
Durchlauf des Sondierungspfades genügt nach Invariante.
Suche erfolgreich, falls v auf s gefunden.
Suche erfolglos, falls erste freie Adresse auf s gefunden.
I
Einfügen eines Wertes v in T :
an der ersten Adresse mit Wert „frei“ oder „gelöscht“ auf
dem Sondierungspfad s von v
I
Löschen eines Wertes v aus T :
Suche nach dem Wert v auf dem Sondierungspfad s von
v,
falls gefunden, überschreiben mit Wert „gelöscht“
Warum?
147
Wahl der Sondierungsfunktion
N
Sondierungsfunktion s : × D → {0, . . . , m − 1}
zu Berechnung des Sondierungspfades für einen Wert v
s = (s1 (v ), s2 (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:
I lineares Sondieren: si = (h(v ) + i) mod m
Modifikation si = (h(v ) + ci) mod m
I quadratisches Sondieren: si+1 = (h(v ) + i 2 ) mod m
I doppeltes Hashing si+1 = (h(v ) + ih0 (x)) mod m
mit zweiter Hashfunktion h0
148
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
149
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
150
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.
151
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)
152
Datenstrukturen für Mengen
I
Arrays, Listen
I
binäre Suchbäume
I
AVL-Bäume
I
Hashtabellen
153
Herunterladen