13. Kapitel: Hashfunktionen

Slides:



Advertisements
Ähnliche Präsentationen
Algorithmen und Datenstrukturen
Advertisements

Algorithmentheorie 08 – Dynamische Programmierung (1)
Randomisierte Algorithmen Präfix Suche und Konsistentes Hashing
Hash-Tabellen und -Funktionen Hash-Tabellen in Java
Definition [1]: Sei S eine endliche Menge und sei p eine Abbildung von S in die positiven reellen Zahlen Für einen Teilmenge ES von S sei p definiert.
Rekursion: Rekurrenz: Algorithmen rufen sich selbst (rekursiv) auf.
Falls Algorithmen sich selbst rekursiv aufrufen, so kann ihr Laufzeitverhalten bzw. ihr Speicherplatzbedarf in der Regel durch eine Rekursionsformel (recurrence,
Eine dynamische Menge, die diese Operationen unterstützt,
Eine dynamische Menge, die diese Operationen unterstützt,
Vorlesung Programmieren II
Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Christian Schindelhauer
Vom graphischen Differenzieren
Prof. Dr. T. Kudraß1 Hash-Verfahren. Prof. Dr. T. Kudraß2 Einführung Drei Alternativen, wie Dateneinträge k* im Index aussehen können: 1. Datensatz mit.
M a r c – o l i v e r p a h l Informatik II – Kapitel 14 Hashing Zusammenfassung des Kapitel 14 Küchlin, Weber, Einführung in die Informatik, 2.Auflage.
Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Claudio Moraga; Gisbert Dittrich
Zusammenfassung der Vorwoche
Kapitel 6: Klassifizierung von Sortiertechniken
7. Natürliche Binärbäume
Gewichtsbalancierte Suchbäume
Durchlaufen eines Binärbaumes
Suche in Texten (Stringsuche )
3. Kapitel: Komplexität und Komplexitätsklassen
Kapitel 6. Suchverfahren
<d,a,s, ,i,s,t, ,e,i,n,e, ,L,i,s,t,e>
Kapitel 3: Listen Lineare Liste: endliche Folge von Elementen eines Grundtyps (n>=0), leere Liste falls n=0 Listenelemente besitzen.
5. Sortier-Algorithmen Vorbemerkungen:
Löschen in B-Bäumen Die B-Baum-Eigenschaft muss wieder hergestellt werden, wenn die Anzahl der Elemente in einem Knoten kleiner als k wird. Durch Ausgleich.
Synonyme: Stapel, Keller, LIFO-Liste usw.
Sortierverfahren Richard Göbel.
Sortierverfahren Richard Göbel.
Effizienz: Indexstrukturen
Algorithmentheorie 04 –Hashing
WS Algorithmentheorie 05 - Treaps Prof. Dr. Th. Ottmann.
Algorithmen und Datenstrukturen
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (13 – Offenes Hashing) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (10 - Suchverfahren) T. Lauer.
Prof. Dr. S. Albers Prof. Dr. Th. Ottmann
Algorithmen und Datenstrukturen
Halbzeit: Kurze Wiederholung
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (19 - Analyse natürlicher Bäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen Halbzeit: Was haben wir bisher gelernt? Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (12 Hashverfahren: Allgemeiner Rahmen) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27 – Kürzeste Wege) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Bäume: Grundlagen und natürliche Suchbäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (18 - Bäume: Durchlaufreihenfolgen, Analyse nat. Bäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (11-1 –Selbstanordnende lineare Listen) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27-Selbstanordnende lineare Listen) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (15 Hashverfahren: Verkettung der Überläufer) Prof. Th. Ottmann.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (21 – Kürzeste Wege) T. Lauer.
Informatik II, SS 2008 Algorithmen und Datenstrukturen Vorlesung 16 Prof. Dr. Thomas Ottmann Algorithmen & Datenstrukturen, Institut für Informatik Fakultät.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
Friedhelm Meyer auf der Heide 1 HEINZ NIXDORF INSTITUTE University of Paderborn Algorithms and Complexity Algorithmen und Komplexität Teil 1: Grundlegende.
Zahlen mit Zahlen ausmessen
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Eine Implementierung einer effiziente externe geordnete (!) lineare Liste Operationen: Search(x) Insert(x) Delete(x)
Sortieralgorithmen Sortieren von Arrays.
Einführung in die Programmierung
Effiziente Algorithmen
Quantum Computing Hartmut Klauck Universität Frankfurt WS 04/
Quantum Computing Hartmut Klauck Universität Frankfurt WS 05/ /23.1.
Polynome und schnelle Fourier-Transformation
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Einführung in die Programmierung Wintersemester 2009/10 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Übung Datenbanksysteme II Index- strukturen
Algorithmen und Datenstrukturen Übungsmodul 11
Programmiersprachen II Fortsetzung Datenstrukturen Hashing Prof. Dr. Reiner Güttler Fachbereich GIS HTW.
Programmiersprachen II Fortsetzung Datenstrukturen Balancierte Bäume 3 Prof. Dr. Reiner Güttler Fachbereich GIS HTW.
 Präsentation transkript:

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

Hash-Tabelle: m = 10 Schlüssel Daten 1 2 3 4 5 6 7 8 9 BOHR D1 1 2 3 4 5 6 7 8 9 BOHR D1 CURIE D2 DIRAC D3 EINSTEIN D4 PLANCK D5 HEISENBERG D7 SCHRÖDINGER D8

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

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.

Eine Kollision ergibt sich, wenn Ki 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.

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

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.

Ü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.

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.

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.

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, ...

Beispiel: Einfüge-Reihenfolge: BECKETT, HESSE, BÖLL, HAUPTMANN, STEINBECK, SACHS, HAMSUN, SARTRE HT: m = 8 Schlüssel Schlüssel 1 2 3 4 5 6 7 1 2 3 4 5 6 7 Lösche

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.

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;

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, ...

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

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

Beispiel: Schlüssel 1 2 3 4 5 6 * * * * * * * * * * * * HT: m = 7 1 2 3 4 5 6 HAYDN * HÄNDEL * VIVALDI * BEETHOVEN * BACH * BRAHMS * CORELLI * * SCHUBERT * LISZT * MOZART * *

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: best case worst case Sn = 1 Sn = n Un = 1 Un = n + 1

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.

Ergebnisse für das lineare Sondieren nach Knuth 1 1 -  Sn  0.5 1 + ------- n m mit 0   = --- < 1 1 ( 1 -  )2 Un  0.5 1 + --------- Abschätzung für offene Hash-Verfahren mit optimierter Kollisions-Behandlung (gleichmäßige HT-Verteilung von Kollisionen) 1 1 -  1 Sn ~ - --- * ln ( 1 -  ) Un ~ --------

Anzahl der Suchschritte in HT Sn, Un Sn, Un 10 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 Un Sn Un Sn   0.1 0.3 0.5 0.7 0.9 0.1 0.3 0.5 0.7 0.9 bei „unabhängiger“ Kollisions-Auflösung bei linearem Sondieren

Modell für separate Überlaufbereiche 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 i - 1 m n - 1 2 * m  2 Sn = 1/n *  1 + ------ = 1 + -------  1 + - i = 1

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 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

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.

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

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 )

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

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

Erweiterungen: dynamische Hashing-Verfahren Reorganisationsfreiheit Viele Vorschläge: Erweiterbares Hashing, Lineares Hashing, ... (  2 Seitenzugriffe )