Algorithmen I

Werbung
Algorithmen I
Prof. Peter Sanders
16.05.2017
Institut für Theoretische Informatik
Web:
https://crypto.iti.kit.edu/index.php?id=799
(Folien von Peter Sanders)
KIT Institut für Theoretische Informatik
1
Hashing (Streuspeicherung)
to hash
≈
völlig durcheinander bringen.
Paradoxerweise hilft das, Dinge wiederzunden
KIT Institut für Theoretische Informatik
2
Hashtabellen
speichere Menge
M ⊆ Element.
e ∈ M.
key(e) ist eindeutig für
unterstütze Wörterbuch-Operationen in Zeit
O(1).
M.insert(e : Element): M := M ∪ {e}
M.remove(k : Key): M := M \ {e},
M.nd(k : Key):
return
e ∈M
key(e)
with key(e)
=k
= k; ⊥
falls nichts gefunden
Anderes Interface: map/partielle Funktion Key→Element
M[k] = M.nd(k)
KIT Institut für Theoretische Informatik
3
Exkurs: Konventionen für Elemente
Viele Datenstrukturen repräsentieren Mengen
(engl. auch collection classes).
Die Mengenelemente
e
haben Schlüssel key(e).
Elementvergleich hier gleichbedeutend mit Schlüsselvergleich.
e = e0
gdw. key(e)
= key(e 0 )
(analog für
e < e0
und
e > e 0 ).
KIT Institut für Theoretische Informatik
4
Hashing: Anwendungen
I Auslieferungsregale der UB Karlsruhe
I Entfernen exakter Duplikate
I Schach (oder andere kombinatorische Suchprogramme):
welche Stellungen wurden bereits durchsucht?
I Symboltabelle bei Compilern
I Assoziative Felder bei Script-Sprachen wie perl oder python
I Datenbank-Gleichheits-Join
(wenn eine Tabelle in den Speicher passt)
I Routenplaner: Teilmengen von Knoten, z. B. Suchraum
I ...
KIT Institut für Theoretische Informatik
5
Überblick
I Grundidee
I Hashing mit verketteten Listen
I Analyse
I Hashing mit Arrays
KIT Institut für Theoretische Informatik
6
Erste Ideen zu Implementierungen
M ⊆ Element.
eindeutig für e ∈ M .
speichere Menge
key(e) ist
unterstütze Wörterbuch-Operationen in Zeit
O(1).
Implementierung mit Listen: Wörterbuchoperationen zu aufwändig
Implementierung mit Feldern: Elemente wo ablegen?
key(e) legt fest, wo
e
abgelegt wird
KIT Institut für Theoretische Informatik
7
Ein (über)optimistischer Ansatz
Eine perfekte Hash-Funktion
bildet Elemente von
M
h
injektiv
h
auf eindeutige Einträge
t[0..m − 1]
t[h(key(e))] = e
der Tabelle
ab, d. h.,
Datenstrukturinvariante:
∀e ∈ M : t[h(key(e))] = e
∧
∀0 ≤ i < m : t[i] ∈ M ∪ {⊥}
M
t
KIT Institut für Theoretische Informatik
8
Kollisionen
Perfekte Hash-Funktionen sind schwer zu nden
h
M
t
Beispiel: Geburtstagsparadox
KIT Institut für Theoretische Informatik
9
Kollisionsauösung
Eine Möglichkeit:
Tabelleneinträge: Elemente
Folgen von Elementen
h
k
M
< >
< >
<>
<>
<>
<
>t[h(k)]
<>
<>
< >
<>
<>
t <>
KIT Institut für Theoretische Informatik
10
Hashing mit verketteten Listen
Implementiere die Folgen in den Tabelleneinträgen
durch einfach verkettete Listen
Datenstrukturinvariante:
h
∀e ∈ M : e ∈ t[h(key(e))]
∧
∀0 ≤ i < m : t[i] ⊆ M
k
M
< >
< >
<>
<>
<>
<
>t[h(k)]
<>
<>
< >
<>
<>
t <>
KIT Institut für Theoretische Informatik
11
Hashing mit verketteten Listen
Implementiere die Folgen in den Tabelleneinträgen
durch einfach verkettete Listen
insert(e): Füge
e
am Anfang von
remove(k): Durchlaufe
Element
e
t[h(key(e))]
ein.
t[h(k)].
mit key(e)
=k
gefunden?
löschen und zurückliefern.
nd(k)
:
Durchlaufe
Element
e
t[h(k)].
mit key(e)
=k
gefunden?
h
zurückliefern.
Sonst:
⊥
zurückgeben.
k
M
< >
< >
<>
<>
<>
<
>t[h(k)]
<>
<>
< >
<>
<>
t <>
KIT Institut für Theoretische Informatik
12
Beispiel
00000000001111111111222222
01234567890123456789012345
abcdefghijklmnopqrstuvwxyz
t
t
t
<axe,dice,cube>
<axe,dice,cube>
<axe,dice,cube>
<hash>
<slash,hash>
<slash,hash>
<hack>
<fell>
<hack>
<fell>
<hack>
<fell>
<chop, clip, lop>
<chop, clip, lop>
<chop, lop>
insert
remove
"slash"
"clip"
KIT Institut für Theoretische Informatik
13
Analyse
h
insert(e): konstante Zeit
remove(k):
nd(k)
O(Listenlänge)
: O(Listenlänge)
Aber wie lang werden die Listen?
Schlechtester Fall:
O(|M|)
Besser wenn wir genug Chaos anrichten?
k
M
< >
< >
<>
<>
<>
<
>t[h(k)]
<>
<>
< >
<>
<>
t <>
KIT Institut für Theoretische Informatik
14
Etwas Wahrscheinlichkeitstheorie
für den Hausgebrauch
1
Hash-Beispiel
Elementarereignisse
Ω
{0..m − 1}Key
E42 = {h ∈ Ω : h(4) = h(2)}
Hash-Funktionen
Ω
von x ∈ Ω. ∑x px = 1
Ereignisse: Teilmengen von
px =Wahrscheinlichkeit
1
Gleichverteilung: px =
|Ω|
P [E ] = ∑x∈E px
Zufallsvariable (ZV) X : Ω → R
!
ph = m−|Key|
P [E42 ] = m1
X = | {e ∈ M : h(e) = 0} |
0-1-Zufallsvariable (Indikator-ZV) I : Ω → {0, 1}
Erwartungswert E[X ] = ∑y ∈Ω py X (y )
E[X ] = |M|
m
Linearität des Erwartungswerts: E[X + Y ] = E[X ] + E[Y ]
KIT Institut für Theoretische Informatik
15
Beispiel: Variante des Geburtstagsparadoxon
Wieviele Gäste muss eine Geburtstagsparty im Mittel haben, damit
mindestens zwei Gäste den gleichen Geburtstag haben?
Gäste (Keys) 1..n.
h ∈ Ω = {0..364}{1..n} .
Deniere Indikator-ZV Iij = 1 gdw h(i) = h(j).
n
n
Anzahl Paare mit gleichem Geburtstag: X = ∑i=1 ∑j=i+1 Iij .
Elementarereignisse:
n
n
E[X ] =E[ ∑
n
∑
Iij ] =
i=1 j=i+1
n
n
=∑
∑
i=1 j=i+1
!
=1 ⇔ n =
n
∑ ∑
P [Iij = 1] =
1
2
E[Iij ]
i=1 j=i+1
r
+
1
22
n(n − 1)
2
·
1
365
+ 730≈ 27.52
KIT Institut für Theoretische Informatik
16
Mehr zum Geburtstagsparadoxon
Standardfomulierung:
Ab wann lohnt es sich zu wetten, dass es zwei Gäste mit gleichem
Geburtstag gibt? Etwas komplizierter. Antwort:
n ≥ 23
m = Hashtabelle der Gröÿe m:
h : 1..n → 0..m − 1 ist nur dann mit
2
Wahrscheinlichkeit perfekt wenn m = Ω(n ).
Verallgemeinerung: Jahreslänge
eine zufällige Hashfunktion
vernünftiger
Riesige Platzverschwendung.
KIT Institut für Theoretische Informatik
17
Analyse für zufällige Hash-Funktionen
Theorem 1
h
∀k : die erwartete Anzahl kollidierender Elemente ist O(1) falls |M| ∈ O(m).
M
Beweis.
< >
< >
<>
<>
<>
<
>t[h(k)]
<>
<>
< >
<>
<>
t <>
k deniere Kollisionslänge X
: h(e) = h(k)} | mit M 0 = {e ∈ M : key(e) 6= k}.
0
0-1 ZV Xe = 1 für h(e) = h(k), e ∈ M und Xe = 0
Für festen Schlüssel
X := | {e ∈
M0
Betrachte die
E[X ] = E[
∑
e∈M 0
Xe ] =
∑
E[Xe ] =
e∈M 0
∑
e∈M 0
P [Xe = 1] =
sonst.
|M 0 |
m
∈ O(1)
Das gilt unabhängig von der Eingabe
M.
KIT Institut für Theoretische Informatik
18
Zufällige Hash-Funktionen?
Naive Implementierung: ein Tabelleneintrag pro Schlüssel.
meist zu teuer
Weniger naive Lösungen: kompliziert, immer noch viel Platz.
meist unsinnig
unrealistisch
KIT Institut für Theoretische Informatik
19
Universelles Hashing
Idee: nutze nur bestimmte einfache Hash-Funktionen
Denition 2
H ⊆ {0..m − 1}Key ist universell
falls für alle x , y in Key mit x 6= y
und zufälligem
P [h(x) = h(y )] =
1
m
h∈H ,
.
Theorem 3
Theorem 1 gilt auch für universelle Familien von Hash-Funktionen.
Beweis.
Für
Ω=H
haben wir immer noch
P [Xe = 1] =
1
m.
Der Rest geht wie vorher.
H
Ω
KIT Institut für Theoretische Informatik
20
Eine einfache universelle Familie
m
sei eine Primzahl, Key
⊆ {0, . . . , m − 1}k
Theorem 4
Für a = (a1 , . . . , ak ) ∈ {0, . .n. , m − 1}k deniere o
ha (x) = a·x mod m, H · = ha : a ∈ {0..m − 1}k .
H · ist eine universelle Familie von Hash-Funktionen
x1
*
a1
+
x2
*
a2
+
x3
*
a3
mod m
= ha(x)
KIT Institut für Theoretische Informatik
21
Beispiel für H ·
a = (a1 , . . . , ak ) ∈ {0, . .n. , m − 1}k deniere o
ha (x) = a·x mod m, H · = ha : a ∈ {0..m − 1}k .
Für
k = 3, m = 11
wähle a = (8, 1, 5).
ha ((1, 1, 2)) = (8, 1, 5) · (1, 1, 2) = 8 · 1 + 1 · 1 + 5 · 2 = 19 ≡ 8 mod
11
KIT Institut für Theoretische Informatik
22
Beweis.
x = (x1 , . . . , xk ), y = (y1 , . . . , yk )
a mit ha (x) = ha (y).
Betrachte
zähle
Für jede Wahl der
∑
ai , i 6= j , ∃
ai x i ≡
1≤i≤k
∑
1≤i≤k
⇔ aj (xj − yj ) ≡
⇔ aj ≡
genau ein
mit
xj 6= yj
mit
ha (x) = ha (y):
aj
ai yi ( mod m)
ai (yi − xi )( mod m)
i6=j,1≤i≤k
(xj − yj )−1
ai (yi − xi )(
i6=j,1≤i≤k
∑
∑
mk−1 Möglichkeiten die ai (mit i 6= j )
mk ist die Gesamtzahl der a, d. h.,
mod m)
auszuwählen.
P [ha (x) = ha (y)] =
mk−1
1
= .
k
m
m
KIT Institut für Theoretische Informatik
23
Bit-basierte Universelle Familien
Sei
m = 2w ,
Key
= {0, 1}k
Bit-Matrix Multiplikation: H ⊕ = hM : M ∈ {0, 1}w ×k
wobei hM (x) = Mx (Arithmetik mod 2, d. h., xor, and)
n
Tabellenzugri:H ⊕[] =
wobei
⊕[]
o
n
o
a
⊕[]
h(t1 ,...,tb ) : ti ∈ {0..m − 1}{0..2 −1}
h(t1 ,...,tb ) ((x0 , x1 , . . . , xb )) = x0 ⊕
Lb
i=1 ti [xi ]
k
x
x2 x1
a
a
x0
w
KIT Institut für Theoretische Informatik
24
Hashing mit Linearer Suche
(Linear Probing)
Zurück zur Ursprungsidee.
Elemente werden direkt in der Tabelle gespeichert.
Kollisionen werden durch Finden anderer Stellen aufgelöst.
linear probing: Suche nächsten freien Platz.
h
Am Ende fange von vorn an.
I einfach
I platz-ezient
I cache-ezient
M
t
KIT Institut für Theoretische Informatik
25
Der einfache Teil
Class
0
: N; h : Key → 0..m − 1)
t=[⊥, . . . , ⊥] : Array [0..m + m0 − 1] of Element
invariant ∀i : t[i] 6= ⊥ ⇒ ∀j ∈ {h(t[i])..i − 1} : t[j] 6= ⊥
BoundedLinearProbing(m, m
Procedure insert(e : Element)
for (i := h(e); t[i] 6= ⊥; i++
assert i < m + m0 − 1
h
) ;
m
t[i] := e
Function nd(k : Key) : Element
for (i := h(k); t[i] 6= ⊥; i++ )
if t[i] = k then return t[i]
return ⊥
M
t
m’
KIT Institut für Theoretische Informatik
26
Remove
Beispiel:
t = [. . . , x , y , z, . . .],
h(z)
remove(x)
invariant ∀i : t[i] 6= ⊥ ⇒ ∀j ∈ {h(t[i])..i − 1} : t[j] 6= ⊥
Procedure remove(k : Key)
for (i := h(k); k 6= t[i]; i++ )
// search k
if t[i] = ⊥ then return
// nothing to do
// we plan for a hole at i.
for (j := i + 1; t[j] 6= ⊥; j++ )
// Establish invariant for t[j].
if h(t[j]) ≤ i then
t[i] := t[j]
// Overwrite removed element
i := j
// move planned hole
t[i] := ⊥
// erase freed entry
KIT Institut für Theoretische Informatik
27
an
tt 0
insert : axe, chop, clip, cube, dice, fell, hack, hash, lop, slash
bo cp
dq er fs
gt hu iv jw kx
1
5
7
9
10
2
3
4
6
8
axe
chop
axe
chop clip axe
chop clip axe cube
chop clip axe cube dice
ly
11
chop
chop
chop
chop
clip
clip
clip
clip
axe
axe
axe
axe
cube
cube
cube
cube
dice
dice
dice hash
dice hash
lop
hack
fell
fell
fell
fell
chop
clip
axe
cube dice hash
lop
slash hack
fell
hash lop slash hack
hash lop slash hack
hash slash slash hack
hash slash
hack
fell
fell
fell
fell
remove
chop
chop
chop
chop
clip
lop
lop
lop
axe
axe
axe
axe
cube
cube
cube
cube
hack
mz
12
clip
dice
dice
dice
dice
KIT Institut für Theoretische Informatik
28
Herunterladen