Motivation 14. Hashing Hash Tabellen, Geburtstagsparadoxon, Hashfunktionen, Perfektes und universelles Hashing, Kollisionsauflösung durch Verketten, offenes Hashing, Sondieren [Ottan/Widayer, Kap. 4.1-4.3.2, 4.3.4, Coren et al, Kap. 11-11.4] Ziel: Tabelle aller n Studenten dieser Vorlesung Anforderung: Schneller Zugriff per Nae 366 367 Naive Ideen Zuordnung Nae s = s 1 s 2... s ls zu Schlüssel k(s) = l s i=1 s i b i b gross genug, so dass verschiedene Naen verschiedene Schlüssel erhalten. Speichere jeden Datensatz an seine Index in eine grossen Array. Beispiel, it b = 100. Ascii-Werte s i. Anna 71111065 Jacqueline 102110609021813999774 Bessere Idee? Allokation eines Arrays der Länge ( > n). Zuordnung Nae s zu ( ls ) k (s) = s i b i od. i=1 Verschiedene Naen können nun denselben Schlüssel erhalten ( Kollision ). Und dann? Unrealistisch: erfordert zu grosse Arrays. 368 369
Abschätzung Abschätzung Annahe: Urnen, n Kugeln (obda n ). n Kugeln werden gleichverteilt in Urnen gelegt. Vielleicht passieren Kollisionen ja fast nie. Wir schätzen ab... Wie gross ist die Kollisionswahrscheinlichkeit? Sehr verwandte Frage: Bei wie vielen Personen (n) ist die Wahrscheinlichkeit, dass zwei a selben Tag ( = 365) Geburtstag haben grösser als 50%? 370 371 Abschätzung P(keine Kollision) = 1 n+1 =! ( n)!. Sei a. Mit e x = 1 + x + x2 2! +... approxiiere 1 a e a. Dait: 1 ( 1 1 ) Es ergibt sich ( 1 2 ) (... 1 n 1 ) e 1+ +n 1 P(Kollision) = 1 e n(n 1) 2. = e n(n 1) 2. Auflösung zu Geburtstagsparadoxon: Bei 23 Leuten ist die Wahrscheinlichkeit für Geburstagskollision 50.7%. Zahl Mit Füllgrad Mit Füllgrad α := n/ ergibt sich (weiter vereinfacht) P(Kollision) 1 e α2 2. P(Kollision) 1 0.5 10% 5% 20% 100 200 300 Der axiale Füllgrad sollte sich an n 2 / orientieren. stat von der leicht besseren Approxiation via Stirling Forel. 372 373
Noenklatur Beispiele guter Hashfunktionen Hashfunktion h: Abbildung aus der Menge der Schlüssel K auf die Indexenge {0, 1,..., 1} eines Arrays (Hashtabelle). h : K {0, 1,..., 1}. Meist K. Es gibt also k 1, k 2 K it h(k 1 ) = h(k 2 ) (Kollision). Eine Hashfunktion sollte die Menge der Schlüssel öglichst gleichässig auf die Positionen der Hashtabelle verteilen. h(k) = k od, Prizahl h(k) = (k r k r ), r irrational, besonders gut: r = 5 1 2. 374 375 Perfektes Hashing Ist i Vorhinein die Menge der verwendeten Schlüssel bekannt? Dann kann die Hashfunktion perfekt gewählt werden. Die praktische Konstruktion ist nicht-trivial. Beispiel: Tabelle der Schlüsselwörter in eine Copiler. Universelles Hashing K > Menge ähnlicher Schlüssel kann ier so gewählt sein, so dass überdurchschnittlich viele Kollisionen entstehen. Unöglich, einzelne für alle Fälle beste Hashfunktion auszuwählen. Jedoch öglich 15 : randoisieren! Universelle Hashklasse H {h : K {0, 1,..., 1}} ist eine Failie von Hashfunktionen, so dass k 1 k 2 K : {h H h(k 1 ) = h(k 2 )} 1 H. 15 Ähnlich wie bei Quicksort 376 377
Universelles Hashing Universelles Hashing Theore Eine aus einer universellen Klasse H von Hashfunktionen zufällig gewählte Funktion h H verteilt i Erwartungswert eine beliebige Folge von Schlüsseln aus K so gleichässig wie nur öglich auf die verfügbaren Plätze. Vorbeerkung zu Beweis des Theores. Definiere it x, y K, h H, Y K: { 1, falls h(x) = h(y), x y δ(x, y, h) = 0, sonst, δ(x, Y, h) = y Y δ(x, y, h), δ(x, y, H) = h H δ(x, y, h). H ist universell, wenn für alle x, y K, x y : δ(x, y, H) H /. 378 379 Universelles Hashing Universelles Hashing ist relevant! Beweis des Theores S K: bereits gespeicherte Schlüssel. x wird hinzugefügt: E H (δ(x, S, h)) = h H δ(x, S, h)/ H = 1 H = 1 H 1 H h H y S δ(x, y, H) y S y S δ(x, y, h) = 1 H H / = S. δ(x, y, h) y S h H 380 Sei p Prizahl und K = {0,..., p 1}. Mit a K \ {0}, b K definiere h ab : K {0,..., 1}, h ab (x) = ((ax + b) od p) od. Dann gilt Theore Die Klasse H = {h ab a, b K, a 0} ist eine universelle Klasse von Hashfunktionen. 381
Behandlung von Kollisionen Beispiel = 7, K = {0,..., 500}, h(k) = k od. Schlüssel 12, 53, 5, 15, 2,, 43 Verkettung der Überläufer Behandlung von Kollisionen Beispiel = 7, K = {0,..., 500}, h(k) = k od. Schlüssel 12, 53, 5, 15, 2,, 43 Direkte Verkettung der Überläufer Hashtabelle 15 2 53 12 Hashtabelle 15 2 53 12 Überläufer 43 5 Überläufer 43 5 382 383 Algorithen zu Hashing it Verkettung search(k) Durchsuche Liste an Position h(k) nach k. Gib wahr zurück, wenn gefunden, sonst falsch. insert(k) Prüfe ob k in Liste an Position h(k). Falls nein, füge k a Ende der Liste ein. delete(k) Durchsuche die Liste an Position h(k) nach k. Wenn Suche erfolgreich, entferne das entsprechende Listeneleent. Analyse (direkt verkettete Liste) 1 Erfolglose Suche. Durchschnittliche Listenlänge ist α = n. Liste uss ganz durchlaufen werden. Durchschnittliche Anzahl betrachteter C n = α. 2 Erfolgreiche Suche. Betrachten die Einfügehistorie: Schlüssel j sieht durchschnittliche Listenlänge (j 1)/. Durchschnittliche Anzahl betrachteter C n = 1 n n (1 + (j 1)/)) = 1 + 1 n j=1 n(n 1) 2 1 + α 2. 385 384
Vor und Nachteile Offene Hashverfahren Vorteile der Strategie: Belegungsfaktoren α > 1 öglich Entfernen von Schlüsseln einfach Nachteile Speicherverbrauch der Verkettung Speichere die Überläufer direkt in der Hashtabelle it einer Sondierungsfunktion s(j, k) (0 j <, k K) Tabellenposition des Schlüssels entlang der Sondierungsfolge S(k) := (h(k) s(0, k) od,..., (h(k) ( 1, k)) od 386 387 Algorithen zu Open Addressing search(k) Durchlaufe Tabelleneinträge geäss S(k). Wird k gefunden, gib true zurück. Ist die Sondierungsfolge zu Ende oder eine leere Position erreicht, gib false zurück. insert(k) Suche k in der Tabelle geäss S(k). Ist k nicht vorhanden, füge k an die erste freie Position in der Sondierungsfolge ein. 16 delete(k) Suche k in der Tabelle geäss S(k). Wenn k gefunden, arkiere Position von k it eine deleted-flag. Lineares Sondieren s(j, k) = j S(k) = (h(k) od, (h(k) 1) od,..., (h(k) + 1) od ) Beispiel = 7, K = {0,..., 500}, h(k) = k od. Schlüssel 12, 53, 5, 15, 2, 15 2 5 53 12 16 Als frei gilt auch eine nicht leere Position it deleted flag. 388 389
Analyse Lineares Sondieren (ohne Herleitung) Diskussion 1 Erfolglose Suche. Durchschnittliche Anzahl betrachteter C n 1 ( ) 1 1 + 2 (1 α) 2 2 Erfolgreiche Suche. Durchschnittliche Anzahl betrachteter C n 1 ( 1 + 1 ). 2 1 α Beispiel α = 0.95 Erfolglose Suche betrachtet i Durchschnitt 200 Tabelleneinträge!? Nachteile des Verfahrens?! Priäre Häufung: Ähnliche Hashaddressen haben ähnliche Sondierungsfolgen lange zusaenhängende belegte Bereiche. 390 391 Quadratisches Sondieren s(j, k) = j/2 2 ( 1) j S(k) = (h(k) + 1, h(k) 1, h(k) + 4, h(k) 4,... ) od Beispiel = 7, K = {0,..., 500}, h(k) = k od. Schlüssel 12, 53, 5, 15, 2, 15 2 53 12 5 Analyse Quadratisches Sondieren (ohne Herleitung) 1 Erfolglose Suche. Durchschnittliche Anzahl betrachteter C n 1 ( ) 1 1 α α + ln 1 α 2 Erfolgreiche Suche. Durchschnittliche Anzahl betrachteter ( ) 1 C n 1 + ln α 1 α 2. 392 393
Diskussion Beispiel α = 0.95 Erfolglose Suche betrachtet i Durchschnitt 22 Tabelleneinträge? Nachteile des Verfahrens?! Sekundäre Häufung: Synonye k und k (it h(k) = h(k )) durchlaufen dieselbe Sondierungsfolge. Double Hashing Zwei Hashfunktionen h(k) und h (k). s(j, k) = j h (k). S(k) = (h(k) h (k), h(k) 2h (k),..., h(k) ( 1)h (k)) od Beispiel: = 7, K = {0,..., 500}, h(k) = k od 7, h (k) = 1 + k od 5. Schlüssel 12, 53, 5, 15, 2, 15 2 5 53 12 394 395 Double Hashing Sondierungsreihenfolge uss Perutation aller Hashadressen bilden. Also h (k) 0 und h (k) darf nicht teilen, z.b. garantiert it pri. h sollte unabhängig von h sein (Vereidung sekundärer Häufung). Unabhängigkeit: P ((h(k) = h(k )) (h (k) = h (k ))) = P (h(k) = h(k )) P (h (k) = h (k )). Unabhängigkeit erfüllt von h(k) = k od und h (k) = 1 + k od ( 2) ( pri). Analyse Double Hashing Sind h und h unabhängig, dann: 1 Erfolglose Suche. Durchschnittliche Anzahl betrachteter C n 1 1 α 2 Erfolgreiche Suche. Durchschnittliche Anzahl betrachteter C n 1 + α 2 + α3 4 + α4 15 α5 18 + < 2.5 397 396
Übersicht α = 0.50 α = 0.90 α = 0.95 C n C n C n C n C n C n Separate Verkettung 1.250 1.110 1.450 1.307 1.475 1.337 Direkte Verkettung 1.250 0.500 1.450 0.900 1.475 0.950 Lineares Sondieren 1.500 2.500 5.500 50.500 10.500 200.500 Quadratisches Sondieren 1.440 2.0 2.850 11.400 3.520 22.050 Double Hashing 1.39 2.000 2.560 10.000 3.150 20.000 398