PowerPoint

Werbung
13. Kapitel: Hashfunktionen
1) Divisionsrest-Verfahren ( kurz: Divisionsverfahren)
h(Ki) = Ki mod q, (q ~ m)
Der entstehende Rest ergibt die relative Adresse in HT.
Beispiel:
Die Funktion nat wandle Namen in natürliche Zahlen um:
nat(Name) = ord (1. Buchstabe von Name ) - ord (“A”)
h (Name) = nat (Name) mod m
G.Heyer
1
Algorithmen und Datenstrukturen
Hash-Tabelle:
m = 10
Schlüssel
0
Daten
1
BOHR
D1
2
CURIE
D2
3
DIRAC
D3
4
EINSTEIN
D4
5
PLANCK
D5
7
HEISENBERG
D7
8
SCHRÖDINGER
D8
6
9
G.Heyer
2
Algorithmen und Datenstrukturen
Divisionsrest- Verfahren: Forderungen an Divisor q
1) m > n
• Belegungsfaktor von HT: Verhältnis von aktuell belegten
Speicherplätzen (n) zur gesamten Anzahl der
Speicherplätze (m)  = na / m
• Für   0.85 erzeugen alle Hash-Funktionen viele
Kollisionen und damit einen hohen Zusatzaufwand.
2) q  gerade Zahl
sonst bleibt h (Ki) bei geradem Ki gerade und bei
ungeradem Ki ungerade.
3) q  bk
b sei die Basis der Schlüsseldarstellung. Wenn q = bk ist,
dann liefert h (Ki) die letzten k Stellen von Ki.
h(Ki) = Ki mod q
G.Heyer
3
Algorithmen und Datenstrukturen
4) q  a * bk  c
a und c seien kleine ganze Zahlen. Der Divisor q soll nicht
benachbart zu einer Potenz des Zahlensystems (in dem die
Division durchgeführt wird) liegen, da sonst
(x + a * bk  c ) mod q ~ x mod q ist, d. h., bei
gleichen Endziffern wiederholt sich fast die gleiche Menge
von Adressen in verschiedenen Zahlenbereichen.
5) q = Primzahl ( größte Primzahl <= m)
Die Hash-Funktion muss etwaige Regelmäßigkeiten in der
Schlüsselverteilung eliminieren, damit nicht ständig die
gleichen Plätze der HT getroffen werden.
Bei äquidistantem Abstand der Schlüssel
Ki + j * K, j = 0, 1, 2, ,... maximiert eine Primzahl die
Distanz, nach der eine Kollision auftritt.
G.Heyer
4
Algorithmen und Datenstrukturen
Eine Kollision ergibt sich, wenn
Ki mod q = (Ki + j * K) mod q
j * K = k * q,
oder
k = 1, 2, 3, ...
Eine Primzahl kann keine gemeinsamen Faktoren mit K
besitzen, die den Kollisionsabstand verkürzen würden.
==> wichtigste Forderung an q !
2) Faltung
• Schlüssel wird in Teile zerlegt, die bis auf das letzte die
Länge einer Adresse für HT besitzen.
• Schlüsselteile werden dann übereinander gefaltet und
addiert.
G.Heyer
5
Algorithmen und Datenstrukturen
3) Mid-Square-Methode
• Schlüssel Ki wird quadriert, t aufeinanderfolgende Stellen
werden aus der Mitte des Ergebnisses für die Adressierung
ausgewählt.
• Es muss also bt = m gelten.
• Mittlere Stellen lassen beste Gleichverteilung der Werte
erwarten.
• Beispiel für b = 2, t = 4, m = 16 :
Ki = 1100100
Ki2 = 10011100010000  h (Ki) = 1000
t
G.Heyer
6
Algorithmen und Datenstrukturen
4) Weitere Verfahren
• Zufallsmethode: Ki dient als Saat für Zufallszahlengenerator
• Ziffernanalyse: setzt Kenntnis der Schlüsselmenge K voraus.
Die t Stellen mit der besten Gleichverteilung der Ziffern
oder Zeichen in K werden von Ki zur Adressierung
ausgewählt.
Bewertung
Das Verhalten einer Hash-Funktion hängt von der gewählten
Schlüsselmenge ab.
Deshalb lassen sie sich auch nur unzureichend theoretisch
oder mit Hilfe von analytischen Modellen untersuchen.
G.Heyer
7
Algorithmen und Datenstrukturen
Über die Güte der verschiedenen Hash-Funktionen liegen
jedoch eine Reihe von empirischen Untersuchungen vor.
• Das Divisionsrest-Verfahren ist im Mittel am
leistungsfähigsten; für bestimmte Schlüsselmengen können
jedoch andere Techniken besser abschneiden.
• Keine Hash-Funktion ist immer besser als alle anderen.
• Wenn die Schlüsselverteilung nicht bekannt ist, dann ist
das Divisionsrest-Verfahren die bevorzugte Hash-Technik.
==> Wenn eine Hash-Funktion gegeben ist, lässt sich immer
eine Schlüsselmenge finden, bei der sie besonders viele
Kollisionen erzeugt.
G.Heyer
8
Algorithmen und Datenstrukturen
Behandlung von Kollisionen
Zwei Ansätze, wenn h (Kq) = h (Kp):
• Es wird für Kp eine freier Platz in HT gesucht ; alle
Überläufer werden im Primärbereich untergebracht
(open adressing).
• Kp wird in einem separaten Überlaufbereich zusammen mit
allen anderen Überläufern gespeichert (separate overflow)
Die Methode der Kollisions-Auflösung entscheidet darüber,
welche Folge und wie viele relative Adressen zur Ermittlung
eines freien Platzes aufgesucht werden.
G.Heyer
9
Algorithmen und Datenstrukturen
Adressfolge bei Speicherung und Suche für Schlüssel Kp sei
h0(Kp), h1(Kp), h2(Kp), ...
• Bei einer Folge der Länge n treten also n-1 Kollisionen auf
• Primärkollision:
h (K p) = h (K q)
• Sekundärkollision:
h i (Kp) = h j(Kq) , i  j
Offene Hash-Verfahren
Speicherung der Synonyme (Überläufer) im Primärbereich
Das eingesetzte Hash-Verfahren muss in der Lage sein, eine
Sondierungsfolge, d. h. eine Permutation aller Hash-Adressen,
zu berechnen.
G.Heyer
10
Algorithmen und Datenstrukturen
1) Lineares Sondieren (linear probing)
Von der Hausadresse aus wird sequentiell (modulo) gesucht. Diese
Vorgehensweise kann mit jedem Hash-Verfahren kombiniert
werden. Offensichtlich werden dabei alle Plätze in HT erreicht:
h0 (K p) = h (K p)
h i (K p) = ( h 0( K p ) - i ) mod m,
G.Heyer
11
i = 1, 2, ...
Algorithmen und Datenstrukturen
Beispiel: Einfüge-Reihenfolge:
BECKETT, HESSE, BÖLL, HAUPTMANN, STEINBECK,
SACHS, HAMSUN, SARTRE
HT: m = 8
Schlüssel
Schlüssel
0
1
2
3
4
5
6
7
G.Heyer
Lösche
12
0
1
2
3
4
5
6
7
Algorithmen und Datenstrukturen
• Irgendeine Primär- oder Sekundärkollision kann eine
Häufung von Primär- oder Sekundärkollision auslösen.
• Löschen: implizit oft Verschiebungen. Entstehende Lücken
in Suchsequenzen sind auszufüllen, da das Antreffen eines
freien Platzes die Suche beendet.
G.Heyer
13
Algorithmen und Datenstrukturen
Suche in einer Hash-Tabelle bei linearem Sondieren
void Linsuche (Key X, Hashtab HT, Cardinal m, Cardinal j)
{
/* Suche in HT bei linearem Sondieren
/*Bei erfolgreicher Suche zeigt j auf Position von X in HT
Cardinal i;
i = H [X];
/* H sei global definierte Hash-Funktion
j=i;
/* unbelegter Eintrag in HT sei durch
/* „ - “ - Zeichen charakterisiert
while ( (HT [ j ] != X) && (HT[ j ] != „ - „ ) )
{
j = (j -1 ) % m;
if ( i == j)
{
printf ( „ X ist nicht in HT \n“);
return ;
}
if ( HT [ j ] == „ - „ ) printf („ X ist nicht in HT \n“);
}
return;
}
G.Heyer
14
*/
*/
*/
*/
*/
Algorithmen und Datenstrukturen
Verbesserung: Modifikation der Überlauffolge
(z.B. durch quadratisches Sondieren)
h0 ( K p)
= h ( K p)
h i+1 ( K p ) = ( hi ( K p ) + f ( i ) ) mod m
oder
h i+1 (K p) = (h i ( Kp ) + f ( i, h ( K p ) ) ) mod m , i= 1, 2, ...
2) Sondieren mit Zufallszahlen
Mit Hilfe eines deterministischen Pseudo-ZufallszahlenGenerators wird die Folge der Adressen [1 ... m-1] mod m
genau einmal erzeugt. Abhängig von k wird eine zufällige
Hashadresse s(j, k) gewählt.
G.Heyer
h0 (K p)
= h (K p)
h i (K p)
= ( h0 (K p) + z i ) mod m
15
, i = 1, 2, ...
Algorithmen und Datenstrukturen
3) Double-Hashing
Einsatz einer zweiten Funktion für die Sondierungsfolge
h0 (Kp)
= h (Kp)
hi (Kp)
= ( h0 (Kp) + i * h‘ (Kp) ) mod m , i = 1, 2, ...
Dabei ist h‘ (K) so zu wählen, dass für alle Schlüssel K die
resultierende Sondierungsfolge eine Permutation aller
Hash-Adressen bildet.
4) Kettung von Synonymen
• Explizite Kettung aller Sätze einer Kollisionsklasse
verringert nicht die Anzahl der Kollisionsklassen; verkürzt
jedoch den Suchpfad beim Aufsuchen eines Synonyms.
• Bestimmung eines freien Überlaufplatzes
(Kollisionsbehandlung) mit beliebiger Methode
G.Heyer
16
Algorithmen und Datenstrukturen
Hash-Verfahren mit separatem Überlaufbereich
Dynamische Speicherplatz-Belegung für Synonyme
• Alle Sätze, die nicht auf ihrer Hausadresse unterkommen,
werden in einem separaten Bereich gespeichert.
• Die Bestimmung der Überlaufadresse kann entweder
durch Double Hashing oder durch Kettung der Synonyme
erfolgen.
• Die Synonym-Kettung erlaubt auch die Möglichkeit, den
Speicherplatz für Überläufer dynamisch zu belegen.
• Suchen, Einfügen und Löschen sind auf Kollisionsklasse
beschränkt.
• Unterscheidung nach Primär- und Sekundärbereich
G.Heyer
17
Algorithmen und Datenstrukturen
Beispiel:
HT:
m=7
Schlüssel
0 HAYDN
*
1 BEETHOVEN *
2 CORELLI
*
3
*
4 SCHUBERT
*
5 MOZART
*
6
*
G.Heyer
HÄNDEL
*
VIVALDI
BACH
*
BRAHMS *
LISZT
*
18
*
Algorithmen und Datenstrukturen
Analyse des Hashing
Kostenmaße
•  = n / m : Belegung von HT mit n Schlüsseln
• Sn = # Suchschritte für das Auffinden eines Schlüssels entspricht den Kosten für erfolgreiche Suche und
Löschen (ohne Reorganisation)
• Un = # der Suchschritte für die erfolglose Suche das Auffinden des ersten freien Platzes entspricht den
Einfügekosten
Grenzwerte:
G.Heyer
best case
worst case
Sn = 1
Sn = n
Un = 1
Un = n + 1
19
Algorithmen und Datenstrukturen
Modell für das lineare Sondieren
• sobald  eine gewisse Größe überschreitet, verschlechtert
sich das Zugriffsverhalten sehr stark.
0
1
2
3
4
5
6
7
8 9 10 11 12 13 14 15 16
• Je länger eine Liste ist, um so schneller wird sie noch
länger werden.
• Zwei Listen können zusammen wachsen (Platz 3 und 14),
so dass durch neue Schlüssel eine Art Verdopplung der
Listenlänge eintreten kann.
G.Heyer
20
Algorithmen und Datenstrukturen
Ergebnisse für das lineare Sondieren nach Knuth
1
Sn  0.5 1 + ------1-
1
Un  0.5 1 + --------( 1 -  )2
n
mit 0   = --- < 1
m
Abschätzung für offene Hash-Verfahren mit optimierter
Kollisions-Behandlung
(gleichmäßige HT-Verteilung von Kollisionen)
1
Un ~ -------1-
1
Sn ~ - --- * ln ( 1 -  )

G.Heyer
21
Algorithmen und Datenstrukturen
Anzahl der Suchschritte in HT
Sn, Un
Sn, Un
10
9
8
7
6
5
4
3
2
1
Un Sn
0.1
0.3
0.5
0.7
0.9
10
9
8
7
6
5
4
3
2
1

Sn
0.1
0.3
0.5
0.7
0.9

bei „unabhängiger“ KollisionsAuflösung
bei linearem Sondieren
G.Heyer
Un
22
Algorithmen und Datenstrukturen
Analyse des Hashing (2)
Modell für separate Überlaufbereiche
• Annahme: n Schlüssel verteilen sich gleichförmig über die
m möglichen Ketten.
• Jede Synonym-Kette hat also im Mittel n/m =  Schlüssel.
Wenn der i-te Schlüssel Ki in HT eingefügt wird, sind in
jeder Kette ( i -1 ) / m Schlüssel. Die Suche nach Ki kostet
also 1 + ( i -1 ) / m Schritte, da Ki an das jeweilige Ende
einer Kette angehängt wird.
Erwartungswert für erfolgreiche Suche:
n
Sn = 1/n * 
i=1
G.Heyer
n-1

= 1 + -------  1 + 2*m
2
i-1
1 + -----m
23
Algorithmen und Datenstrukturen
Bei der erfolglosen Suche muss immer die ganze Kette
durchlaufen werden. Die Kostenformel hat somit folgende
Struktur:
Un = 1 + 1 * WS ( zu einer Hausadresse existiert ein Überläufer)
+ 2 * WS (zu einer Hausadresse existieren zwei Überläufer)
+ 3 * .....
Un   - e
-

0.5
Sn
1.25 1.37 1.5
Un
1.11 1.22 1.37 1.72
G.Heyer
0.75
1
1.5
2
3
4
5
1.75
2
2.5
3
3.5
2.14 3.05 4.02 5.01
24
Algorithmen und Datenstrukturen
Separate Kettung ist auch der „unabhängigen“ KollisionsAuflösung überlegen.
Hashing ist i. a. ein sehr leistungsstarkes Verfahren. Selbst bei
starker Überbelegung (  > 1 ) erhält man bei separater
Kettung noch günstige Werte.
G.Heyer
25
Algorithmen und Datenstrukturen
Dynamische Hash-Verfahren
Wachstumsprobleme bei statischen Verfahren
• Statische Allokation von Speicherbereichen:
Speicherausnutzung ?
• Bei Erweiterung des Adressraumes: Rehashing
==> Kosten, Verfügbarkeit, Adressierbarkeit
S
A‘
A
h
h‘
==> alle Sätze erhalten eine neue Adresse
G.Heyer
26
Algorithmen und Datenstrukturen
Entwurfsziele
• Eine im Vergleich zu statischen Hashing dynamische
Struktur erlaubt Wachstum und Schrumpfung des
Hash-Bereichs ( Datei )
• keine Überlauftechniken
• Zugriffsfaktor  2 für direkte Suche
Viele konkurrierende Ansätze
• Extendible Hashing ( Fagin et al., 1978 )
• Virtual Hashing und Linear Hashing ( Letwin, 1978, 1980 )
• Dynamic Hashing (Larson, 1978 )
G.Heyer
27
Algorithmen und Datenstrukturen
Zusammenfassung
Hash-Funktion
• berechnet Speicheradresse des Satzes
• zielt auf bestmögliche Gleichverteilung der Sätze im
Hash-Bereich
Hashing bietet im Vergleich zu Bäumen eine eingeschränkte
Funktionalität
• direkter Schlüsselzugriff
• i. a. kein sortiert sequentieller Zugriff
• ordnungserhaltendes Hashing nur in Sonderfällen
anwendbar
• statisches Verfahren
G.Heyer
28
Algorithmen und Datenstrukturen
Idealfall: Direkte Adressierung
• nur in Ausnahmefällen möglich ( „dichte“ Schlüsselmenge)
• jeder Satz kann mit einem Zugriff referenziert, eingefügt
oder gelöscht werden
Hash-Verfahren im Hauptspeicher
• Standard: Divisions-Rest-Verfahren
• bei offenen Hash-Verfahren ist der
Belegungsgrad
  0.85
dringend zu empfehlen
• Kollisionsbehandlung mit separatem Überlaufbereich
i. a. effizienter und einfacher zu realisieren
G.Heyer
29
Algorithmen und Datenstrukturen
Erweiterungen: dynamische Hashing-Verfahren
• Reorganisationsfreiheit
• Viele Vorschläge:
Erweiterbares Hashing,
Lineares Hashing, ...
(  2 Seitenzugriffe )
G.Heyer
30
Algorithmen und Datenstrukturen
Herunterladen