Hashing einfache Methode um Wörtebücher zu implementieren, d.h. Hashing unterstützt die Operationen Search, Insert, Delete. Worst-case Zeit für Search: Θ(n). In der Praxis jedoch sehr gut. Unter gewissen Annahmen, erwartete Suchzeit O(1). Hashing Verallgemeinerung von direkter Adressierung durch Arrays. 1
Direkte Adressierung mit Arrays Schlüssel für Objekte der dynamischen Menge aus U:={0,,m-1}. Menge U wird Universum genannt. Nehmen an, dass alle Objekte unterschiedliche Schlüssel haben. Legen Array T[0,,m-1] an. Position k in T reserviert für Objekt mit Schlüssel k. T[k] verweist auf Objekt mit Schlüssel k. Falls kein Objekt mit Schlüssel k in Struktur, so gilt T[k]=NIL. 2
Operationen bei direkter Adressierung (1) Direct - Address - 1. returnt [ k] Search ( T,k ) Direct - 1. T Direct - 1. T Address - Insert x [ key[ x ] Address - Delete [ key[ x ] NIL ( T,x) ( T,x) 3
Operationen bei direkter Adressierung (2) Laufzeit jeweils O(1). Direkte Adressierung nicht möglich, wenn Universum U sehr groß ist. Speicherineffizient, wenn Menge der aktuell zu speichernden Schlüssel deutlich kleiner als U ist. 4
Direkte Adressierung - Illustration Schlüssel / 1 9 4 Universum U 0 6 Benutzte Schlüssel K 2 8 3 5 7 / / / / / 2 3 5 8 Satellitendaten 5
Hashing Idee (1) Nehmen an, dass die Menge K der zu speichernden Schlüssel immer kleiner als das Universum U ist. Hashing hat dann Speicherbedarf Θ ( K ) Insert wie bei direkter Adressierung ( ) Zeit für Search und Delete ebenfalls O ( 1) Durchschnitt bei geeigneten Annahmen. Legen Array [ 0,,m 1]. Zeit für O 1., aber nur im T K an, wobei m < U. Nennen T Hashtabelle. Benutzen Hashfunktion h:u { 0, K,m-1}. Verweis auf Objekt mit Schlüssel k in [ h( k) ] T. 6
Hashing - Illustration Universum U k 1 k 4 k 5 k Benutzte 2 k Schlüssel K 3 0 m 1 / / / / / / h h ( k 1 ) ( ) k 4 ( k ) h( ) h = h( k 3 ) 2 k 5 7
Hashing Idee (2) Da m < U, gibt es Objekte, deren Schlüssel auf denselben Wert gehasht werden, d.h., es gibt Schlüssel k 1,k2 mit k1 k2 und h( k1) = h( k2 ). Dieses wird Kollision genannt. Verwaltung von Kollision erfolgt durch Verkettung. Speichern Objekte, deren Schlüssel auf den Hashwert h abgebildet werden, in einer doppelt verketteten Liste L h. Dann verweist T [ h] auf den Beginn der Liste, head. speichert also [ ] L h Insert, Delete, Search jetzt mit Listenoperationen. 8
Operationen bei Kollisionsverwaltung Chained - Hash - Search 1. Suche nach Element ( T,k ) mit Schlüssel k in Liste T [ h( k )]. Chained 1. Füge - x Hash - Insert am Kopf der ( T,x ) Liste T [ h( key [ x] )] ein. ( T,x ) h( key [ x] ) Chained - Hash - Delete 1. Entferne x aus Liste T [ ]. Laufzeit für Insert O(1). Laufzeit für Delete, Search proportional zur Länge von T[h(k)]. 9
Hashing mit Listen - Illustration Universum U k 1 k 4 k 5 Benutzte k 2 k Schlüssel K 3 / / / / / / k 1 k 4 k k 2 5 k 3 10
Analyse von Hashing mit Listen (1) m Größe der Hashtabelle T, n Anzahl der gespeicherten Objekte. Dann heisst α:=n/m der Lastfaktor von T. α ist die durchschnittliche Anzahl von Elementen in einer verketteten Liste. Werden alle Objekte auf denselben Wert gehasht, so benötigt Suche bei n Elementen Zeit Θ(n). Dasselbe Verhalten wie verkettete Listen. Im Durchschnitt aber ist Suche deutlich besser, falls eine gute Hashfunktion h benutzt wird. Gute Hashfunktion streut Werte wie zufällige Funktion. 11
Einfaches uniformes Hashing Definition 12.1: Wenn wir annehmen, dass bei jedem neuen Objekt mit Schlüssel k, die Hashfunktion h den Schlüssel k gleichverteilt und unabhängig von anderen bereits festgelegten Hashwerten auf die möglichen Hashwerte abbildet, so sprechen wir von einfachem uniformen Hashing. 12
Analyse von einfachem uniformen Hashing (1) Für j = 0, 1, K,m 1sei n j Größe der Liste T [ j]. Dann gilt: n = n0 + n1 + L + nm 1. Erwartungswert E [ n ] j von n j ist α = n / m. Nehmen zusätzlich an, dass die Hashfunktion h in Zeit O(1) ausgewertet werden kann. 13
Analyse von einfachem uniformen Hashing (2) Satz 12.2: Bei einfachem uniformen Hashing benötigt eine nicht erfolgreiche Suche im Erwartungswert Zeit Θ(1+α). Satz 12.3: Bei einfachem uniformen Hashing benötigt eine erfolgreiche Suche im Erwartungswert und bei zufälligem Suchobjekt Zeit Θ(1+α). In beiden Fällen: Ist n=o(m), so ist erwartete Laufzeit O(1). 14
Einfaches uniformes Hashing - Realisierung Einfaches uniformes Hashing kann realisiert werden, indem 1. Jedem einzufügenden Objekt beim Einfügen ein Schlüssel zufällig gleichverteilt zugewiesen wird. 2. Für die Hashfunktion h und für jeden Hashwert w 0, 1, K, m 1 gilt: { } Die Anzahl der Schlüssel k, die auf w gehasht werden, ist genau U /m. Hashfunktion mit 2.Eigenschaft ist z.b. h(k)=k mod m, falls U Vielfaches von m ist. 15
Einfaches uniformes Hashing Realisierung 1.Eigenschaft ist sehr unrealistisch. Stattdessen Hashfunktionen, die Schlüssel regelmäßig streuen und Regelmäßigkeiten in den Daten umgehen. Beispiel: Schlüssel sind Eigennamen. Alphabetisch nahe Eigennamen sollten weit auseinander liegende Hashwerte erhalten. 16
Beispiele für Hashfunktionen 1. h(k)=k mod m (Divisionsmethode) 2. h(k)= m(ka mod 1), mit ka mod 1 = ka- ka (Multiplikationsmethode) Hashing mit Divisionsmethode schnell, pro Hashwert eine Division. m sollte keine Zweierpotenz sein. Andernfalls besteht Hashwert nur aus unteren Bits des Schlüssels. Gute Wahl ist Primzahl m, die nicht sehr nah an Zweierpotenzen liegt. 17
Multiplikationsmethode (1) Methode: h( k ) m( k A mod 1 ) =. Parameterwahl: p 1. Wahl von m irrrelevant, häufig m = 2. 2. Wahl von A wichtig, häufig gewählt als gute Approximation zum goldenen Schnitt ( 5 1) / 2. 18
Multiplikationsmethode (2) Berechnung h(k): p w (bei m = 2, A = s / 2, p w, k 2 w für alle Schlüssel k ) 1. Berechne r 2 w = k A. w w 2. Schreibe r als r12 + r0, 0 r0 2 1. 3. Binärdarstellung von ( k ) h gegeben durch die oberen p Bits von r 0. 19
Multiplikationsmethode - Illustration w Bits k s = A 2 w r 1 r 0 h(k ) extrahiere p Bits 20
Offene Adressierung (1) Hashing mit Kollisionsvermeidung weist Objekt mit gegebenen Schlüssel feste Position in Hashtabelle zu. Bei Hashing durch offene Adressierung wird Objekt mit Schlüssel keine feste Position zugewiesen. Position abhängig von Schlüssel und bereits belegten Positionen in Hashtabelle. Für neues Objekt wird erste freie Position gesucht. Dazu wird Hashtabelle nach freier Position durchsucht. Reihenfolge der Suche hängt vom Schlüssel des einzufügenden Objekts ab. 21
Offene Adressierung (2) Keine Listen zur Kollisionsvermeidung. Wenn Anzahl eingefügter Objekte ist m, dann sind keine weiteren Einfügungen mehr möglich. Listen zur Kollisionsvermeidung möglich, aber Ziel von offener Adressierung ist es, Verfolgen von Verweisen zu vermeiden. Da keine Listen benötigt werden, kann die Hashtabelle vergrößert werden. Suchen von Objekten in der Regel schneller, da keine Listen linear durchsucht werden müssen. 22
Offene Adressierung (3) Laufzeit für Einfügen nur noch im Durchschnitt Θ(1). Entfernen von Objekten schwierig, deshalb Anwendung von offener Adressierung oft nur, wenn Entfernen nicht benötigt wird. 23
Hashfunktionen bei offener Adressierung Hashfunktion legt für jeden Schlüssel fest, in welcher Reihenfolge für Objekte mit diesem Schlüssel nach freier Position in Hashtabelle gesucht wird. Hashfunktion h von der Form { 0, 1,,m 1} { 0, 1, K, 1} h : U K m. m:=größe der Hashtabelle. Verlangen, dass für alle Schlüssel k die Folge ( h( k, 0),h( k, 1), K,h( k,m 1) ) eine Permutation der 0, 1, K,m 1 ist. Folge ( ) ( ( k, 0),h( k, 1),,h( k,m 1) ) h K heisst Testfolge bei Schlüssel k. 24
Einfügen bei offener Adressierung ( T,k ) Hash - Insert 1 i 0 2 repeat j h( k,i ) 3 if T [ j] = NIL 4 thent [ j] k 5 else i i + 1 6 until i = m 7 error "Hashtabelle vollständig gefüllt" Dabei zur Vereinfachung angenommen, dass keine Satellitendaten vorhanden, d.h., Objekt ist Schlüssel. 25
Offene Adressierung - Illustration 79 69 98 72 50 26
Suchen bei offener Adressierung ( T,k ) Hash - Search 1 i 0 2 repeat j h( k,i ) 3 if T [ j] = k 4 then return j 5 else i i + 1 6 until T [ j] = NIL i = m 7 return NIL 27
Probleme bei Entfernen Können Felder i mit gelöschten Schlüsseln nicht wieder mit NIL belegen, denn dann wird Suche nach Schlüsseln, bei deren Einfügung Position i getestet wird, fehlerhaft sein. Mögliche Lösung ist, Felder gelöschter Schlüssel mit DELETED zu markieren. Aber dann werden Laufzeiten für Hash-Insert und Hash-Delete nicht mehr nur vom Lastfaktor α=n/m abhängen. Daher Anwendung von offener Adressierung nur, wenn keine Objekte entfernt werden müssen. 28
Mögliche Hashfunktionen 1. h' : U { 0, 1, K, m 1} Funktion. Lineares Hashen: h k,i ( ) ( h' ( k ) + i ) mod m =. 2. h' : U {, 1, K,m 1} Funktion, c,c 0. 0 1 2 Quadratisches Hashen: h k,i = h' k + 2 c i c i mod. ( ) ( ) ( ) m 1 + 2 29
Vergleich Hashfunktionen Im linearen und quadratischen Hashen bestimmt erste gestestete Position gesamte Testfolge. Damit jeweils nur m mögliche Testfolgen. Bei linearem Testfolgen zusätzlich lange zusammenhängende Folgen von besetzten Positionen 30
Analyse von offener Adressierung (1) Definition 12.4: Nehmen wir an, dass für jeden Schlüssel jede der m! Permutationen der Folge (0,1,...,m-1) mit gleicher Wahrscheinlichkeit die Testfolge ist, so nennen wir dieses uniformes offenes Hashen. Satz 12.5 : Ist der Lastfaktor einer Hashtabelle bei uniformen offenem Hashing α, so ist die erwartete Anzahl von Tests bei einer nicht erfolgreichen Suche 1/(1- α). Korollar 12.6: Ist der Lastfaktor einer Hashtabelle bei uniformen offenem Hashing α, so ist die erwartete Anzahl von Tests bei einer Einfügung 1/(1- α). 31
Analyse von offener Adressierung (2) Satz 12.7: Ist der Lastfaktor einer Hashtabelle bei uniformen offenem Hashing α, so ist bei einem zufälligen Suchobjekt die erwartete Anzahl von Tests bei einer erfolgreichen Suche höchstens 1 1 ln α 1 α. 32
Hashing Zusammenfassung (1) Hashing ist eine einfache Methode Wörterbücher zu implementieren. Hashing unterstützt also Einfügen, Entfernen und Suchen von Objekten. Einfügen und Entfernen benötigen im worst-case konstante Laufzeit. Suchen benötigt bei geeigneten Annahmen im Erwartungswert ebenfalls konstante Zeit. In der Praxis ist Hashing sehr erfolgreich. 33
Hashing Zusammenfassung (2) Haben zwei Varianten kennen gelernt: 1. Hashing mit Kollisionsverwaltung durch Listen. 2. Offene Adressierung zur Kollisionsvermeidung. 34
Universelles Hashen - Idee Bei jeder Hashfunktion gibt es schlechte Eingaben, d.h., eine Folge von Einfügeoperationen, so dass Suche Zeit linear in der Anzahl der gespeicherten Objekte benötigt. Es müssen Objekte und Schlüssel so gewählt werden, dass alle Hashwerte identisch sind. Lösung besteht darin, nicht eine Hashfunktion zu wählen, sondern eine ganze Menge von Hashfunktionen. Unabhängig von Schlüsseln wird dann eine der Hashfunktionen ausgewählt. Führt zu universellem Hashing. 35
Universelles Hashen - Definition Definition 12.8: Sei H eine endliche Menge von Funktionen von U nach { 0, 1, K,m 1}. Die Menge H heisst universell, wenn für je zwei Schlüssel k,l mit k l gilt: Die Anzahl der Funktionen h H mit h ( k ) = h( l ) ist höchstens m H. 36