g.heyer algorithmen und datenstrukturen 1 13. kapitel: hashfunktionen 1) divisionsrest-verfahren (...
Post on 05-Apr-2015
104 Views
Preview:
TRANSCRIPT
G.Heyer Algorithmen und Datenstrukturen1
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 Algorithmen und Datenstrukturen2
Hash-Tabelle:m = 10 Schlüssel Daten
0
1
2
3
4
5
6
7
8
9
BOHR D1
CURIE D2
DIRAC D3
EINSTEIN D4
PLANCK D5
HEISENBERG D7
SCHRÖDINGER D8
G.Heyer Algorithmen und Datenstrukturen3
Divisionsrest- Verfahren: Forderungen an Divisor q1) 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 Algorithmen und Datenstrukturen4
4) q a * bk ca 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 Algorithmen und Datenstrukturen5
Eine Kollision ergibt sich, wennKi mod q = (Ki + j * K) mod q oder
j * K = k * q, 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 Algorithmen und Datenstrukturen6
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 Algorithmen und Datenstrukturen7
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 Algorithmen und Datenstrukturen8
Ü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 Algorithmen und Datenstrukturen9
Behandlung von KollisionenZwei 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 Algorithmen und Datenstrukturen10
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 Algorithmen und Datenstrukturen11
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, i = 1, 2, ...
G.Heyer Algorithmen und Datenstrukturen12
Beispiel: Einfüge-Reihenfolge:
BECKETT, HESSE, BÖLL, HAUPTMANN, STEINBECK, SACHS, HAMSUN, SARTRE
HT: m = 8
01234567
Schlüssel Schlüssel01234567
Lösche
G.Heyer Algorithmen und Datenstrukturen13
• 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 Algorithmen und Datenstrukturen14
Suche in einer Hash-Tabelle bei linearem Sondierenvoid 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 Algorithmen und Datenstrukturen15
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-Zufallszahlen-Generators 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.
h0 (K p) = h (K p)
h i (K p) = ( h0 (K p) + z i ) mod m , i = 1, 2, ...
G.Heyer Algorithmen und Datenstrukturen16
3) Double-HashingEinsatz 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 Algorithmen und Datenstrukturen17
Hash-Verfahren mit separatem ÜberlaufbereichDynamische 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 Algorithmen und Datenstrukturen18
Beispiel:
HAYDN *
HT:
m = 7
0
1
2
3
4
5
6
BEETHOVEN
CORELLI
SCHUBERT
MOZART
HÄNDEL *
BACH BRAHMS **
*
*
*
*
* *
LISZT *
*VIVALDI
Schlüssel
G.Heyer Algorithmen und Datenstrukturen19
Analyse des HashingKostenmaß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: best case worst case
Sn = 1 Sn = n
Un = 1 Un = n + 1
G.Heyer Algorithmen und Datenstrukturen20
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 Algorithmen und Datenstrukturen21
Ergebnisse für das lineare Sondieren nach Knuth
Sn 0.5 1 + ------- 1
1 - mit 0 = --- < 1 n
mUn 0.5 1 + ---------
1
( 1 - )2
Abschätzung für offene Hash-Verfahren mit optimierter Kollisions-Behandlung
(gleichmäßige HT-Verteilung von Kollisionen)
Sn ~ - --- * ln ( 1 - ) Un ~ -------- 1
1
1 -
G.Heyer Algorithmen und Datenstrukturen22
Anzahl der Suchschritte in HT
10 9 8 7 6 5 4 3 2 1
Sn, Un
0.1 0.3 0.5 0.7 0.9
Un
10 9 8 7 6 5 4 3 2 1
0.1 0.3 0.5 0.7 0.9
Sn Un
Sn
bei linearem Sondieren bei „unabhängiger“ Kollisions-Auflösung
Sn, Un
G.Heyer Algorithmen und Datenstrukturen23
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:
Sn = 1/n * 1 + ------ = 1 + ------- 1 + - i = 1
n i - 1
m
n - 1
2 * m
2
G.Heyer Algorithmen und Datenstrukturen24
Bei der erfolglosen Suche muss immer die ganze Kettedurchlaufen 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 0.75 1 1.5 2 3 4 5
Sn 1.25 1.37 1.5 1.75 2 2.5 3 3.5
Un 1.11 1.22 1.37 1.72 2.14 3.05 4.02 5.01
G.Heyer Algorithmen und Datenstrukturen25
Separate Kettung ist auch der „unabhängigen“ Kollisions-Auflö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 Algorithmen und Datenstrukturen26
Dynamische Hash-VerfahrenWachstumsprobleme bei statischen Verfahren
• Statische Allokation von Speicherbereichen:
Speicherausnutzung ?• Bei Erweiterung des Adressraumes: Rehashing
==> Kosten, Verfügbarkeit, AdressierbarkeitS
h
h‘
A
A‘
==> alle Sätze erhalten eine neue Adresse
G.Heyer Algorithmen und Datenstrukturen27
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 Algorithmen und Datenstrukturen28
ZusammenfassungHash-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 Algorithmen und Datenstrukturen29
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 Algorithmen und Datenstrukturen30
Erweiterungen: dynamische Hashing-Verfahren
• Reorganisationsfreiheit
• Viele Vorschläge: Erweiterbares Hashing,
Lineares Hashing, ...
( 2 Seitenzugriffe )
top related