Kapitel 4 Streuen Wir behandeln nun Implementationen ungeordneter Wörterbücher, in denen die Schlüssel ohne Beachtung ihrer Sortierreihenfolge gespeichert werden dürfen, verlangen aber, dass es sich bei den Schlüsseln um Zahlen handelt. Dies ist keine starke Voraussetzung, weil sich die Elemente anderer Schlüsseluniversen als Zahlen codieren lassen. typisch in JAVA: Speicheradresse Bezeichnungen: (Schlüssel-) Universum Schlüsselmenge Hashtabelle Object.hashCode U ⊆ N0 K ⊆ U, |K| = n H[0, . . . , m − 1] (Array von Zeigern auf Datenelemente) h : U → {0, . . . , m − 1} wird jedem zulässigen hash (engl.): streuen Schlüssel k ∈ U seine Speicherstelle H[h(k)] in der Hashtabelle H zugewiesen. Durch eine Hashfunktion Im Idealfall gilt für die Menge K⊆U der vorkommenden Schlüssel k1 6= k2 ∈ K =⇒ h(k1 ) 6= h(k2 ) (h|K injektiv) weil Einfügen, Suchen und Löschen dann jeweils in können. 4.1 Beispiel (Hashfunktionen) 1. h(k) = k mod m für Primzahl m (Divisions- oder Kongruenzmethode) 60 Θ(1) realisiert werden Algorithmen und Datenstrukturen (WS 2008/09) 61 √ ≈ 0, 61803 2. h(k) = bm · (kα − bkαc)c z.B. für α = φ−1 = 5−1 2 (Multiplikationsmethode) Die n+1 Intervalle nach Einfügen von 1, . . . , n haben nur 3 verschiedene Gröÿen; bei α = φ−1 am ähnlichsten. 4.1 Kollisionen 4.1 h(k1 ) = h(k2 ) für einige h1 , h2 ∈ K . Kollisionen, k1 , k2 heiÿen Synonyme. Im Allgemeinen ist allerdings bezeichnen wir mit Dies pm,n := P (keine Kollisionen) = 1· m−1 · m−2 · . . . · m−n+1 , falls Schlüssel durch m m m h gleichmäÿig gestreut werden, d.h. alle Positionen gleichwahrscheinlich sind. 4.2 Beispiel (Geburtstagsparadoxon) p365,22 > 0.5 > p365,23 Anschauliche Deutung: bei 23 oder mehr Personen ist die Wahrscheinlichkeit, dass zwei am gleichen Tag Geburtstag haben, gröÿer als die Wahrscheinlichkeit, dass alle an verschiedenen Tagen Geburtstag haben. Herleitung: pm,n = Qn−1 i=0 m−i m Qn−1 = (1 − mi ) Qi=1 n 1 Pn−1 n−1 −i/m ≈ = e− m i=1 i = e−( 2 )/m i=1 e Für welches n ist pm,n ≈ 1/2? n e−( 2)/m = 12 ⇔ − n2 /m = ln 21 n ⇔ = m ln 2 2 q n(n−1) 2 ⇒ n ≈ p 2(ln 2) · m (≈ 22.49 für m = 365) goldener Schnitt Algorithmen und Datenstrukturen (WS 2008/09) Erwartete Anzahl Kollisionen Xij = 1 0 falls Sei h(ki ) = h(kj ) (Kollision E(Xij ) = 1/m für ! X Xij = i<j Im Beispiel war von ki , kj ) sonst Bei gleichmäÿiger Streuung ist E(X) = E 62 X E(Xij ) = X i<j m = 365, i<j i 6= j . n 1/m = · 1/m 2 somit gilt hier E(X) = <1 ≥1 für für n < 27 n ≥ 27 Im Allgemeinen gilt E(X) ≥ 1 ⇔ n(n − 1) ≥ 2m, also etwa bei n≥ √ 2m. 4.3 Def inition (Belegungsfaktor) Wir denieren den Belegungsfaktor (load factor) als β = mn . → entscheidend für Nutzen Erwartete Anzahl leerer Felder? i ∈ {0, . . . , m − 1} Element m−1 mit Wahrscheinlichkeit m Die Wahrscheinlichkeit, dass Position i ? k ∈ K steht nicht an Position = 1 − m1 . nicht belegt ist, ist damit " 1 m P (i ∈ / {h(k1 ), . . . , h(kn )}) = (1 − m1 )n = (1 − ) | {zm } ≈e−1/m = E(Xi ) für Xi = #β ≈ e−β 0 H[i] 1 H[i] belegt frei P P P E(X) = E( Xi ) = E(Xi ) = e−β = m · e−β . y Die erwartete Anzahl belegter Einträge ist β = 1/2 : β=1 : 1 − e−1/2 ≈ 0.39 1 − e−1 ≈ 0.63 m − m · e−β = m(1 − e−β ). Belegung Belegung 39% 63% Algorithmen und Datenstrukturen (WS 2008/09) 4.2 Kollisionsbehandlung 4.2.1 Idee 63 Verkettung Die Hashtabelle wird als Array von Zeigern auf Listen implementiert, wobei die Listen alle Schlüssel mit gleichem Hashfunktionswert enthalten. 4.4 Beispiel (h(k) = k mod p) 0 p−1 1 ··· H: 4.5 Def inition (Sondieren) Wenn die Hashtabelle über Verkettung realisiert wird, nden bei find eventuell mehrere Zugrie auf Zeiger statt (Sondieren). Um die Anzahl der Sondierschritte zu analysieren, denieren wir A(m, n) := mittlere Anzahl bei erfolgreicher Suche. A0 (m, n) := mittlere Anzahl, falls Schlüssel nicht in der Hashtabelle ist. Wir gehen wieder davon aus, dass für das verwendete Modell P (h(k) = i) = gilt. 1 m ∀k ∈ U, i ∈ {0, . . . , m − 1} Algorithmen und Datenstrukturen (WS 2008/09) 64 Die mittlere Länge der Listen ist gerade der Belegungsfaktor n 0 Also ist A (m, n) = 1 + β = 1 + . m β= n m ∈ [0, ∞). A(m, n): Die Suche nach ki ergibt genau die Sondierungen wie beim Einfügen von ki , wenn vorher k1 , . . . , ki−1 eingefügt wurden. Im Mittel ist damit P Pn−1 Pn−1 1 1 i 0 A(m, n) = n1 n−1 i=0 A (m, i) = n i=0 (1 + m ) = 1 + nm · i=0 i Zu = 1+ (n−1)·n 2nm Statistische Eigenschaften Hashtabelle T β 2 − 1 2m ≤1+ β = 1 (n = m). T (ki )i=1,2,3,... , ki ∈ U β 2 Dann sind 63% der besetzt, 37% sind frei (s.o.). Wie groÿ muss damit alle Plätze in Sei Sei =1+ n im Mittel sein, belegt sind? m(i) die Ank1 , . . . , ki und sei ik := min{i|m(i) = erstmals den k -ten Platz in T . die Folge in T einzufügender Schlüssel. Sei Coupon Collector Problem zahl belegter Plätze nach Einfügen von k}, d.h. Einfügen von kik belegt Wir betrachten eine Zufallsvariable X mit Xk = iP k − ik−1 m X= k=1 Xk Dann ist die gesuchte Zahl für i: m(i) gerade 1 2 3 4 5 k1 k2 k3 k4 k5 · · · 1 2 i1 i2 3 ik−1 ≤ i < ik . E[X]. ··· 4 i3 X1 X2 X3 Sei n i4 X4 i5 X5 ··· k0 k 00 m−1 m im−1 Xm−1 Dann ist pk := P (i + 1 = ik ) = m−k+1 m E[Xk ] = p1k P P P m E[X] = E[ m Xk ] = m E[Xk ] = m 1 1 1 m−k+1 Pm 1 = m · k=1 k = m · Hm ≈ m · ln m im Xm Index k etwas unglücklich bei k für key Algorithmen und Datenstrukturen (WS 2008/09) 65 n = m ln m Im Mittel sind also Einfügeoperationen notwendig, um alle m ln m = ln m > 1. Positionen in der Hashtabelle zu füllen. Dann ist β = m 4.2.2 Idee Open Hashing In jedem Feld der Hashtabelle (daher H wird nur ein Element gespeichert β ≤ 1). Füge Schlüssel Füge Schlüssel Wähle eine Folge k2 Für die Folge k1 (di )i=1,2,... , di ∈ Z (di )i h(k1 ) = i, H[i] = k1 . h(k2 ) = i, H[i] besetzt. y freien Platz in H . ein: ein (Kollision): H[(h(k) + di ) lineares Sondieren: double Hashing: und teste mod m], i = 1, 2, 3, . . . di = i di = i2 di = i · h0 (k), sollte m h0 : U → {1, . . . , m − 1} 0 ist mit h (k) 6= 0 ∀k ∈ U . wobei zweite Hashfunktion prim sein! Warum? Einfügen und Suchen ist damit klar, Löschen ist aber ein Problem. 4.7 Beispiel Sei h(k) = h(k0 ) = i und füge k, k 0 ein: H: k k0 i i+1 k. y Anschlieÿend versagt die Suche nach Lösung: markiere gelöschte Schlüssel als gelöscht eine Hier Index h0 ? 4.6 Problem Lösche dann Finde gibt es verschiedene Wahlen: quadratisches Sondieren: • m k0! bei Algorithmen und Datenstrukturen (WS 2008/09) 66 • bei Suche werden sie behandelt wie belegte Felder • beim Einfügen wie freie Felder • ungünstig, wenn oft Elemente gelöscht werden, da die Suche verteuert. 4.8 Problem Clusterbildung 4.9 Beispiel (lineares Sondieren) H: ··· ··· i i+1 Nächster einzufügender Schlüssel: P (h(k) = i + 1) = P (h(k) = i) = 1 m 5 m k∈U ⇒ Cluster wachsen tendentiell Analyse lineares Sondieren double Hashing 1 A ≈ 12 (1 + 1−β ) 1 1 0 A ≈ 2 (1 + (1−β)2 ) 1 A ≈ β1 ln( 1−β ) 1 0 A ≈ 1−β Beweis. lineares Sondieren: schwer, s. Schöning S.140-141. double Hashing: (idealisierende) Annahme: Sondierungen erfolglosen Suche von k Referenz h1 (k), h2 (k), . . . zur mit n =1−β P (H[hi (k)] ist frei) = 1 − m E[Anzahl Sondierungen bis freies Feld gefunden] = 1 1−β Algorithmen und Datenstrukturen (WS 2008/09) Also A0 (n, m) = 67 1 . 1−β A(n, m) = = ≈ = Pn−1 0 Pn−1 1 Pn−1 1 1 m 1 i=0 A (m, i) = n i=0 1− i = n i=0 m−i n m 1 1 1 1 ( + · · · + m ) = β (Hm − Hm−n ) β m−n+1 m 1 (ln m − ln(m − n)) = β1 ln m−n β 1 1 ln 1−β β 4.3 Kollisionsvermeidung 4.3.1 Ziel Streufunktionen gleichmäÿige Streuung durch Hashfunktion, wie in der Berechnung der Kollisionswahrscheinlichkeiten unterstellt. Problem → K ⊆ U h(k1 ) = H(k2 ) ∀k1 , k2 ∈ K Wir wissen nicht, welche Schlüssel Schlimmstenfalls ist Sondieren bei Suche entspricht linearer Suche Schlüsselmengen K ⊆U gespeichert werden. O(n). führen zu sehr verschiedenen Laufzeiten. Versuche daher, die Wahrscheinlichkeit für schlechtes Laufzeitverhalten besser auf diese zu verteilen. Idee Wähle aus einer Menge von Hashfunktionen H ⊆ {h : U → {0, . . . , m − 1}} zufällig eine aus. 4.3.2 Universelles Streuen 4.10 Def inition (universelles Streuen) Eine Familie von Streufunktionen H ⊆ {h : U → {0, . . . , m − 1}} heiÿt universell, falls |H| |{h ∈ H : h(k1 ) = h(k2 )}| ≤ m ∀k1 , k2 ∈ U. Algorithmen und Datenstrukturen (WS 2008/09) Bei zufälliger Wahl h∈H sind wir dann berechtigt, 68 P (h(k1 ) = h(k2 )) = 1 m anzunehmen. 4.11 Satz Ist H universell, dann ist für k ∈ {k1 , . . . , kn } = K ⊆ U bei zufällig gewähltem h ∈ H die erwartete Anzahl Kollisionen gerade mn = β . Beweis. Sei Cij eine Zufallsvariable mit Cij = Da H 1 0 h(ki ) = h(kj ) sonst P (Cij = 1) = m1 , und es folgt für k = ki X X |K| = β. Cij = E(Cij ) ≤ m universell ist, ist E kj ∈K\{ki } kj ∈K\{ki } Die erwartete Anzahl Kollisionen entspricht dann also wie erhot dem Belegungsfaktor β. 4.12 Satz Die Familie von Streufunktionen Hp = {(ak + b mod p) mod m : 0 < a < p, 0 ≤ b < p} , p prim, p > m ist universell. Beweis. Sei ha,b ∈ Hp Betrachte zunächst für mit ha,b (k) = (ak + b mod p) mod m. 0 k, k ∈ {0, . . . , p − 1} r = (ak + b) mod p s = (ak 0 + b) mod p Dann ist r − s ≡ |{z} a (k − k 0 ) mod p, also r 6= s falls k 6= k 0 , p prim ist. {0, . . . , p − 1}, sondern weil 6=0 Es gibt also zunächst keine Kollisionen der Zahlen diese werden nur permutiert. Algorithmen und Datenstrukturen (WS 2008/09) Auÿerdem liefert jede der denn gegeben r 6= s 69 (p − 1) · p Wahlen für (a, b) ein anderes Paar r 6= s, können wir nach a = (r − s) · (k − k 0 )−1 | {z } Inverses bzgl. b = (r − ak) mod p Zp mod p p(p − 1) Paare (r, s) mit r 6= s gibt, liegt a, b zufällig gewählt, dann erhalten wir also auch r= 6 s ∈ {0, . . . , p − 1} mit gleicher Wahrscheinlichkeit. auösen. Weil es aber auch nur eine Bijektion vor. Werden jedes Paar k 6= k 0 ∈ U Die Kollisionswahrscheinlichkeit von entspricht damit der Wahr- r ≡ s mod m für zufällig gewählte r 6= s ∈ {0, . . . , p − 1}. die Anzahl der s mit r 6= s und r ≡ s mod m höchstens scheinlichkeit, dass Für festes r ist lpm m −1 ≤ p+m−1 p−1 −1 = m m und wegen der zufälligen Wahl aus den p − 1 möglichen s 6= r ist die Kollisik 6= k 0 ∈ U höchstens m1 . Also ist Hp universell. onswahrscheinlichkeit für Wir wollen nun noch eine andere universelle Familie von Streufunktionen betrachten. Annahme U Zerlege K⊆U besteht aus Bitstrings fester Länge in Blöcke der Länge m, m ist prim. blog mc ··· k: kr k1 y 0 ≤ ki < m, k0 Wir denieren die Menge von Hashfunktionen durch ha (k) = r X i = 0, . . . , r HB = {ha : U → {0, . . . , m − 1}} ! ai ki mod m i=0 wobei a = (ar , . . . , a0 ) ∈ {0, . . . , m − 1}r+1 . Damit gilt |HB | = mr+1 . Algorithmen und Datenstrukturen (WS 2008/09) 70 4.13 Satz HB ist universell. Beweis. i = 0. k 6= k 0 ∈ U , dann ki 6= ki0 ha ∈ HB gilt dann Seien Für ein 0 ha (k) = ha (k ) ⇔ r X ai ki ≡ i=0 r X für ein ai ki0 i ∈ {0, . . . , r}. OBdA. sei mod m i=0 ⇔ a0 (k0 − k00 ) ≡ r X ai (ki0 − ki ) mod m i=1 ⇔ a0 ≡ k00 )−1 (k0 − | {z mult. Inv. in } (Zm ,+,·) r X ai (ki0 − ki ) y Für alle Wahlen von (ar , . . . , a1 ) ∈ {0, . . . , m − 1}r a0 ∈ {0, . . . , m − 1} mit ha (k) = ha (k 0 ). Also gilt P (Kollision k 6= k 0 ) = mod m i=1 existiert genau ein | {a : ha (k) = ha (k 0 )} | 1 mr = r+1 = . |HB | m m 4.4 Ausblick • viele andere Techniken zur Kollisionsbehandlung, z.B. Cuckoo-Hashing. • viele andere Techniken zur Konstruktion von Hashfunktionen, z.B. perfektes Hashing (für statische Schlüsselmengen). • viele andere Anwendungen, z.B. Bloom-Filter. . s. Übung