30.01.2014 Aufrufe

Kapitel 6

Kapitel 6

Kapitel 6

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

<strong>Kapitel</strong> 6 <br />

HASHING <br />

Algorithmen & Datenstrukturen <br />

Prof. Dr. Wolfgang Schramm


Übersicht <br />

1 <br />

1. Einführung <br />

2. Algorithmen <br />

3. Eigenscha?en von <br />

Programmiersprachen <br />

4. Algorithmenparadigmen <br />

5. Suchen & SorGeren <br />

6. Hashing <br />

7. Komplexität von Algorithmen <br />

8. Abstrakte Datentypen (ADT) <br />

9. Listen <br />

10. Bäume <br />

11. Graphen


Lernziele des <strong>Kapitel</strong>s <br />

2 <br />

2<br />

¨ Kennenlernen von Hashing bzw. <br />

was die MoGvaGon für Hashing <br />

ist? <br />

¨ Verstehen wie Hashing <br />

funkGoniert. <br />

¨ Verstehen, was eine <br />

HashfunkGon ist. <br />

¨ Behandlung von Kollisionen <br />

beim Hashing verstehen. <br />

¨ Einsatzmöglichkeiten für <br />

Hashing kennenlernen.


Inhalt <br />

3 <br />

o<br />

o<br />

o<br />

o<br />

o<br />

o<br />

o<br />

o<br />

o<br />

o<br />

o<br />

Hashing <br />

NotaGonen <br />

HashfunkGon bzw. Streuwer_unkGon <br />

Hashtabelle <br />

Beispiele <br />

Kollisionen und Kollisionsstrategien <br />

Offenes bzw. Geschlossenes Hashing <br />

Komplexität <br />

Anwendungsgebiete von Hashing <br />

Java Hashtable-­‐Klasse <br />

Programmierbeispiel


Hashing <br />

4 <br />

o<br />

o<br />

o<br />

Speichermethode <br />

¤<br />

¤<br />

bei großen Datenbanken <br />

beschleunigt das Finden von Daten <br />

Die Grundidee des Hashing-­‐Verfahrens <br />

¤<br />

Hash-­‐FunkGon: Schlüsselwert à Speicheradresse <br />

GrundoperaBonen <br />

¤<br />

¤<br />

¤<br />

Einfügen <br />

Löschen <br />

Suchen <br />

0<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7


Anwendungsgebiete <br />

5 <br />

o<br />

o<br />

o<br />

o<br />

Datenbanken <br />

¤<br />

Index für Tabellen <br />

à unter günsGgen Bedingungen <br />

„ideale“ Zugriffszeiten <br />

Compiler <br />

¤<br />

InterpretaGon von Symboltabellen <br />

Betriebssysteme <br />

¤<br />

ImplemenGerung von Seitentabellen <br />

SonsGge ApplikaGonen <br />

¤<br />

¤<br />

ImplemenGerung von Caches <br />

ImplemenGerung von Mengen


Hashing: DefiniGonen 1/6 <br />

6 <br />

o<br />

o<br />

o<br />

o<br />

U sei die Menge der möglichen Schlüssel. <br />

S ⊆ U sei die Menge der zu speichernden Schlüssel mit |S| = n. <br />

Ein Behälter (Bucket) kann ein mit einem Schlüssel zu idenGfizierendes <br />

Element aufnehmen. <br />

Eine Hashtabelle H ist eine Menge von nummerierten Behältern <br />

B 0 ,B 1 ,B 2 ,….B m-­‐1 mit |H| = m. <br />

¤<br />

Anmerkung: <br />

häufig ist eine Hashtabelle ein Array und <br />

der Bucket ein Arrayplatz


7 <br />

¨<br />

Eine HashfunkBon ist eine ganzzahlige FunkGon <br />

Hashing: DefiniGonen 2/6 <br />

h : U →{0,...,<br />

h( u ) = a<br />

m −1}<br />

die einem Schlüssel u den Hashwert a zuordnet, der den Behälter B a <br />

bezeichnet. <br />

Anmerkung: bei Hasharray: statt Hashwert auch oft Hashindex


Beispiel Namen <br />

8 <br />

Schlüssel: mögliche Schlüssel U = [A-­‐Z][a-­‐z]* <br />

zu speichernde Schlüssel S = <br />

Hashtabelle: Array 0..7 of Integer Array 0..7 of List of Integer<br />

HashfunkGon: h(u) = <br />

Gelöst (1):<br />

h(u) = mod 8<br />

Zu lösen (1): Länge der Hash-Tabelle müsste unendlich sein.<br />

mod <br />

Zu lösen (2): „Eva“ und „Ann“<br />

haben gleich viele Buchstaben<br />

à „Kollision“<br />

Gelöst (2):<br />

Liste <br />

alternativ zu (2):<br />

falls a[i] besetzt,<br />

wähle a[i+1], usw.


Hashing: DefiniGonen 3/6 <br />

11 <br />

¨<br />

Anmerkung: <br />

¤ Eine HashfunkBon wird o? noGert als <br />

mit <br />

h : f ( u)<br />

mod m<br />

f (u)∈ Ν<br />

m = |H| <br />

H Hashtabelle<br />

|H| Länge der<br />

Hashtabelle<br />

u ganzzahliger<br />

Schlüssel<br />

d.h. <br />

<br />

<br />

f liefert eine „gut verteilte“ Abbildung auf N. <br />

Die modulo-­‐OperaGon reduziert die Zahlen auf die Länge der Hash-­‐<br />

Tabelle


Hashing: DefiniGonen 4/6 <br />

12 <br />

¨<br />

Die Schlüsseldichte ist das Verhältnis zu speichernde zu mögliche Schlüssel, <br />

d.h. <br />

S / U<br />

¨<br />

Der Belegungsfaktor ist das Verhältnis zu speichernde Schlüssel zu Anzahl <br />

der Behälter <br />

S /<br />

B<br />

U: mögliche Schlüssel<br />

S: zu speichernde Schlüssel<br />

B: Behälter


Hashing: DefiniGonen 5/6 <br />

14 <br />

o Der Füllgrad α ist das Verhältnis <br />

¤<br />

¤<br />

aktuell gespeicherte Schlüssel zu <br />

Länge der Hashtabelle, d.h. <br />

α = a / m<br />

mit<br />

m = |H| bzw. m = |B| <br />

a = Anzahl gespeicherter Schlüssel <br />

Anmerkung <br />

Offensichtlich gilt: <br />

je höher der Füllgrad, um so größer die Wahrscheinlichkeit, dass zwei Schlüssel <br />

auf den gleichen Hash-­‐Wert abgebildet werden („Kollision“).


Beispiel 1/4 <br />

15 <br />

Aufgabe <br />

o<br />

Verteilung von Monatsnamen auf 17 <br />

Behälter 0..16 <br />

Lösung <br />

o<br />

Namen werden als Strings dargestellt <br />

→ Umwandlung in Zahlen notwendig <br />

¤<br />

¤<br />

nur Großbuchstaben <br />

f("A") = 1, f("B") = 2, usw. <br />

A 1<br />

B 2<br />

C 3<br />

D 4<br />

E 5<br />

F 6<br />

G 7<br />

H 8<br />

I 9<br />

J 10<br />

K 11<br />

L 12<br />

M 13<br />

N 14<br />

O 15<br />

P 16<br />

Q 17<br />

R 18<br />

S 19<br />

T 20<br />

U 21<br />

V 22<br />

W 23<br />

X 24<br />

Y 25<br />

Z 26


Beispiel 2/4 <br />

16 <br />

¨<br />

Als HashfunkGon nehmen wir <br />

¤<br />

¤<br />

f<br />

=∑<br />

( x) ( x)<br />

3<br />

= 〈〈 Summe der Ordinalzahl der ersten 3 Buchstaben von<br />

h(x) = f x<br />

( ) mod 17 = ( x ) 3<br />

! mod 17<br />

Beispiel: <br />

h(Februar) = (6+5+2) mod 17 = 13 mod 17 = 13 <br />

h(August) = (1+21+7) mod 17 = 29 mod 17 = 12 <br />

x〉〉


Beispiel 3/4 <br />

17 <br />

0 NOV 9 JUL<br />

1 APR , DEZ<br />

10<br />

2 MAE 11 JUN<br />

3 12 AUG<br />

4 13 FEB , OKT<br />

5 14<br />

6 MAI , SEP<br />

15<br />

7 16<br />

8 JAN<br />

• Etliche Buckets bleiben leer <br />

– Füllgrad α = Anteil der belegten Plätze in %, d.h. <br />

α = m / n mit m := Anzahl der Elemente <br />

• Es kann zu Kollisionen kommen! <br />

Es fehlen noch:<br />

SEP, OKT, DEZ<br />

A 1<br />

B 2<br />

C 3<br />

D 4<br />

E 5<br />

F 6<br />

G 7<br />

H 8<br />

I 9<br />

J 10<br />

K 11<br />

L 12<br />

M 13<br />

N 14<br />

O 15<br />

P 16<br />

Q 17<br />

R 18<br />

S 19<br />

T 20<br />

U 21<br />

V 22<br />

W 23<br />

X 24<br />

Y 25<br />

Z 26


Beispiel 4/4 <br />

18 <br />

APR, DEZ à 1 <br />

MAI, SEP à 6 <br />

FEB, OKT à 13 <br />

… mehrere Schlüssel werden auf denselben Behälter abgebildet. <br />

à Kollision <br />

è Auflösung<br />

l dem Behälter hinzufügen à Verketten (lineare Liste)<br />

l neuen Behälter suchen à Sondieren<br />

l vermeiden à perfektes Hashing


Wahrscheinlichkeit für Kollision<br />

19 <br />

P<br />

k<br />

= 1−<br />

mit 1 ≤ m ≤ n <br />

n⋅(<br />

n −1)<br />

⋅(<br />

n − 2) ⋅...<br />

⋅(<br />

n − m + 1)<br />

m<br />

n<br />

n ⋅ (n-­‐1) ⋅ … ⋅ (n-­‐m+1): Anzahl der Möglichkeiten, kollisionsfrei m Elemente <br />

zu verteilen <br />

n m : Anzahl m Elemente <br />

zu verteilen <br />

=<br />

n!<br />

( n − m)!<br />

n<br />

m<br />

¨<br />

Beispiele <br />

¤ Monatsnamen <br />

¤ „Geburtstage in Schulklassen“ <br />

n m P k<br />

17 12 0,99<br />

365 22 0,48<br />

365 23 0,51<br />

365 50 0,97


Hashing: DefiniGonen 6/6 <br />

20 <br />

¨<br />

Eine Kollision tri auf, wenn zwei Schlüssel auf den gleichen Hashwert <br />

abgebildet werden: <br />

h( a ) = h( b)<br />

mit <br />

a ≠ b<br />

.


Eigenscha?en einer HashfunkGon <br />

21 <br />

o<br />

o<br />

o<br />

surjekBv <br />

¤<br />

d.h. alle Behälter sollten erfasst werden. <br />

gleichverteilend <br />

¤<br />

d.h. jeder Behälter sollte mit gleicher Wahrscheinlichkeit getroffen <br />

werden. <br />

einfach <br />

¤<br />

d.h. sie sollte mit minimalen Aufwand berechenbar sein.


Kollisionsstrategien <br />

22 <br />

o<br />

VerkeSen <br />

o<br />

Sondieren <br />

¤<br />

¤<br />

Lineares Sondieren <br />

QuadraGsches Sondieren


Offenes bzw. geschlossenes Hashing <br />

23 <br />

Problem : Was passiert wenn Anzahl Schlüssel > Anzahl Speicherplätze <br />

Lösung : <br />

1. Offenes Hashing:<br />

manchmal auch als<br />

geschlossen bzgl. der<br />

Indexpositionen bezeichnet<br />

!<br />

Jeder Behälter kann beliebig viele Elemente aufnehmen. Für jeden Behälter wird <br />

eine verkeete Liste angelegt, in die alle Schlüssel eingefügt werden, die auf <br />

diesen Behälter abgebildet werden. <br />

2. Geschlossenes Hashing:<br />

manchmal auch als<br />

offen bzgl. der<br />

Indexpositionen bezeichnet<br />

Hier darf jeder Behälter nur eine Konstante Anzahl b ≥ 1 von Schlüsseln <br />

aufnehmen.<br />

!


Offenes Hashing: Verkeen <br />

24 <br />

…<br />

…<br />

3<br />

4<br />

5<br />

…<br />

…<br />

Maerz<br />

Januar<br />

April<br />

Dezember<br />

o<br />

o<br />

o<br />

Ein Behälter kann mehr als ein Element fassen <br />

Alle Schlüssel s mit h(s) = a werden in B a abgelegt <br />

als lineare Liste <br />

Gefahr: Entartung zur linearen Liste à Zugriffszeit wächst rapide


Geschlossenes Hashing: Lineares Sondieren 1/3 <br />

25 <br />

o<br />

o<br />

Pro Behälter ein Schlüssel <br />

Bei Kollision <br />

¤<br />

Linear in einer Richtung nächsten freien Behälter suchen <br />

o<br />

o<br />

Formal <br />

h i<br />

( h(<br />

x)<br />

i) mod m<br />

( x)<br />

= +<br />

i=0;<br />

while (occupied(h i (x)) do<br />

i++;<br />

od;<br />

// hash-key is h i (x) <br />

Gefahr: Folge von besetzten Feldern vergrößert sich (Verklumpung) <br />

à Kollisionswahrscheinlichkeit steigt.


26 <br />

Geschlossenes Hashing: Lineares Sondieren 2/3


Geschlossenes Hashing: Lineares Sondieren 3/3 <br />

27 <br />

o<br />

Varianten <br />

1. Linear in einer Richtung <br />

den nächsten freien Behälter suchen, <br />

mit Sprüngen der Länge c <br />

Beispiel <br />

c = 7; h(a) = 27 <br />

falls 27 besetzt, … 27 + 7 = 34 mod m <br />

falls 34 besetzt, … 34 + 7 = 41 mod m etc. <br />

2. Linear in beiden Richtungen (alternierend) <br />

Beispiel <br />

h(a) = 27 <br />

falls 27 besetzt, … 27 – 1*7 = 20 mod m <br />

falls 20 besetzt, … 20 + 2*7 = 34 mod m <br />

falls 34 besetzt, … 34 – 3*7 = 13 mod m etc.


28 <br />

¨<br />

Geschlossenes Hashing: QuadraGsches Sondieren <br />

Wie lineares Sondieren, jedoch <br />

¤ Schriweite quadraGsch (nicht linear) / alternierend <br />

Beispiel <br />

h(a) = 27 <br />

falls besetzt, … 27 + 1 2 = 28 mod m <br />

27 – 1 2 = 26 mod m <br />

27 + 2 2 = 31 mod m <br />

27 – 2 2 = 23 mod m <br />

27 + 3 2 = 36 mod m etc. <br />

¨<br />

Formal: <br />

h ( x)<br />

i<br />

=<br />

⎛⎛<br />

⎜⎜h(<br />

x)<br />

+<br />

⎜⎜<br />

⎝⎝<br />

( −1)<br />

i+<br />

1<br />

⎡⎡ i ⎤⎤<br />

.<br />

⎢⎢2⎥⎥<br />

2<br />

⎞⎞<br />

⎟⎟<br />

⎟⎟<br />

⎠⎠<br />

mod m


29 <br />

Liste: kein Problem <br />

Sondieren <br />

¤<br />

¤<br />

Element kann nicht <br />

einfach gelöscht <br />

werden, da sonst die <br />

Kee unterbrochen <br />

wäre. <br />

Bsp.: FEB verursacht <br />

Lücke, OKT wird nicht <br />

gefunden. <br />

Mögliche Lösungen <br />

¤<br />

Element wird nicht <br />

gelöscht, sondern nur <br />

zum Überschreiben <br />

markiert. <br />

Löschen von Elementen <br />

0 NOV 9 JUL<br />

1 APR 10<br />

2 MAE Lineares 11 Sondieren JUN<br />

3 DEZ 12 AUG<br />

4 13 FEB<br />

5 14 OKT<br />

6 MAI 15<br />

7 SEP 16<br />

8 JAN !<br />

Prof. Dr. M. Gumbel • WS09 • ADS: Hashing<br />

Folie 29


Komplexität 1/2 <br />

30 <br />

Größe der Hashtabelle: N <br />

o<br />

o<br />

Aufwand im besten Fall <br />

¤<br />

Berechnung des Hashwertes unabhängig von n: <br />

O(1) <br />

Aufwand im schlechtesten Fall <br />

¤<br />

Ganze Hashtabelle muss durchsucht werden <br />

O(N) <br />

(Hashtabelle wg. Kollision zu lin. Liste entartet)


Komplexität 2/2 <br />

31 <br />

Größe der Hashtabelle: N <br />

o Aufwand im mileren Fall (bei sondieren) <br />

¤ Wahrscheinlichkeit für Behälter j: 1/N <br />

¤ Wahrscheinlichkeit einer Kollision: <br />

n abhängig vom Füllgrad α <br />

n Wahrscheinlichkeit für „Behälter belegt“: α <br />

n …nächster Behälter belegt: α 2 <br />

n … übernächstes Bucket belegt: α 3 etc <br />

¤ erfolgloses Suchen: 1 + α + α 2 + α 3 + ... = <br />

1 ⎛⎛ 1 ⎞⎞<br />

¤ erfolgreiches Einfügen: ln⎜⎜<br />

⎟⎟<br />

α ⎝⎝1−α<br />

⎠⎠<br />

1<br />

1−α


32 <br />

Prof. Dr. M. Gumbel • WS09 • ADS: Hashing<br />

Komplexität: Übersicht <br />

Operation Fall Liste oder Sondieren<br />

add bester O(1)<br />

durchschnittlich<br />

⎛⎛ 1 ⎞⎞<br />

O⎜⎜<br />

⎟⎟<br />

⎝⎝1−α<br />

⎠⎠<br />

schlechtester<br />

O(m)<br />

contains bester O(1)<br />

durchschnittlich<br />

⎛⎛ 1 1 ⎞⎞<br />

O⎜⎜<br />

ln ⎟⎟ /<br />

erfolgreich/-los ⎝⎝α 1−α ⎠⎠<br />

schlechtester<br />

O(m)<br />

remove bester O(1)<br />

durchschnittlich<br />

⎛⎛ 1 1 ⎞⎞<br />

O⎜⎜<br />

ln ⎟⎟<br />

⎝⎝α 1−α ⎠⎠<br />

schlechtester<br />

O(m)<br />

⎛⎛ 1 ⎞⎞<br />

O⎜⎜<br />

⎟⎟<br />

⎝⎝1−α<br />

⎠⎠<br />

Folie 32


Optimaler Füllgrad α<br />

33 <br />

¨ Ab Füllgrad von ca. 80 % ist das Verhalten schlecht. <br />

Erfolgreiche Suche<br />

Erfolglose Suche,<br />

Einfügen, Löschen<br />

1 1<br />

ln<br />

α 1−α<br />

1<br />

1−α<br />

Prof. Dr. M. Gumbel • WS09 • ADS: Hashing<br />

Folie 33


Rehashing<br />

34 <br />

¨ Füllgrad zu groß oder das Array voll: à Rehashing <br />

¤ Array wird vergrößert und <br />

¤ alle Elemente werden neu eingefügt. <br />

¨ Vorteil: Zum Löschen markierte Elemente können ebenfalls <br />

freigegeben werden. <br />

¨ Sog. dynamisches Hashen passt Arraygröße automaGsch an. <br />

Prof. Dr. M. Gumbel • WS09 • ADS: Hashing<br />

Folie 34


Java Hashtable-­‐Klasse <br />

35 <br />

Für die ImplementaGon von Hashtabellen steht uns in Java unmielbar die <br />

Klasse Hashtable zur Verfügung. Sie hat die folgenden Methoden: <br />

Hashtable(): der Konstruktor für die DefiniGon einer leeren Hashtabelle <br />

elements(): Rückgabe aller Daten aus der Hashtabelle <br />

isEmpty(): Abfrage, ob die Hashtabelle leer ist <br />

get(): liefert Element gemäß Schlüsselwertangabe


Java Hashtable-­‐Klasse <br />

36 <br />

keys(): gibt alle (belegten) Schlüsselwerte der Hashtabelle zurück <br />

put(): speichert Element gemäß Schlüsselwert in Hashtabelle <br />

remove(): en_ernt referenziertes Hashtabellenelement <br />

size(): gibt Anzahl gespeicherter Elemente in der Hashtabelle zurück <br />

clear(): en_ernt alle Schlüssel und die Elemente aus der Hashtabelle


Java Hashtable-­‐Klasse <br />

37 <br />

contains(): prü?, ob sich ein Element in der Hashtabelle befindet <br />

containsKey(): prü?, ob sich ein Schlüsselwert in der Hashtabelle befindet <br />

clone(): erzeugt einen Klone einer Hashtabelle <br />

toString(): generiert eine String-­‐RepräsentaGon einer Hashtabelle <br />

rehash(): führt das Rehashing für eine Hashtabelle durch.


38 <br />

Programmierbeispiel


39 <br />

Programmierbeispiel

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!