Praktische Einführung und Programmierung
Stefan Bosse
Universität Koblenz - FB Informatik
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer ::
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Umgang mit Kollision und Überläufer
Folgende Verfahren können eingesetzt werden wenn eine Kollision festgestellt wird, d.h. der mit h(k1) berechnete Platz ist bereits mit einem Schlüssel k2 mit k1 ≠ k2 belegt, d.h. das einzufügende Element wird zum Überläufer
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Umgang mit Kollision und Überläufer
Werden zwei Datensätze dem gleichen Bucket zugeteilt, dann spricht man von einer Kollision. Wir benötigen also Methoden um Kollisionen zu behandeln. Die führt zu folgender Idee:
Zusammegefasst gibt es also zwei Lösungsansätze:
Jede Tabellenzelle wird um eine Liste oder Suchbaum erweitert, in denen die kollidierenden Datensätze untergebracht werden.
Oder: Im Fall einer Kollision such man nach einer alternativen Position. Diese Technik nennt man Sondieren.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Sei N = 10 und h(x) = x mod 10. Werden die Datensätze 100, 42, 5, 333, 19, 666, 202, 36 und 2 in eine Hashtabelle eingetragen, so ergibt sich folgende Situation:
Beispiel für die Kollisionsbehandlung mit linearen Listen
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Zwei Methoden können angewendet werden:
Separate Verkettung der Überläufer
Direkte Verkettung der Überläufer
Gegeben sei eine Hashtabelle t der Größe N mit einer Hashfunktion h(k): k -> index ∈ [0,N-1].
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Widmayer Mix aus Hashtabelleneintrag und Verkettung
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Suchen nach Schlüssel k: Beginne bei t[h(k)] und folge den Verweisen der Überlaufkette, bis entweder k gefunden wurde (erfolgreiche Suche) oder das Ende der Überlaufkette erreicht ist (erfolglose Suche).
Einfügen eines Schlüssels k: Suche nach k; die Suche verläuft erfolglos (sonst wird k nicht eingefügt) und endet am Ende einer Überlaufkette oder bei t[h(k)].
Entfernen eines Schlüssels k: Suche nach k; die Suche verläuft erfolgreich (sonst kann k nicht entfernt werden).
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Allerdings fällt auf, daß die unterschiedlichen Fälle (Schlüssel in Hashtabelle oder in Überlaufkette, gegebenenfalls Nachziehen des ersten Überläufers in die Hashtabelle beim Entfernen, usw.) einige Abfragen erfordern, die die Laufzeit der Operationen spürbar beeinträchtigen.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Allerdings fällt auf, daß die unterschiedlichen Fälle (Schlüssel in Hashtabelle oder in Überlaufkette, gegebenenfalls Nachziehen des ersten Überläufers in die Hashtabelle beim Entfernen, usw.) einige Abfragen erfordern, die die Laufzeit der Operationen spürbar beeinträchtigen.
Wenn man bereit ist, unter Umständen etwas Speicherplatz zu opfern, so kann man auch einfach alle Datensätze in den Überlaufketten speichern; in der Hashtabelle benötigt man dann nur Zeiger auf den Listenanfang.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Jedes Element der Hashtaelle ist ein Zeiger auf eine (Überlauf-) Kette. Im wesentlichen handelt es sich hierbei also stets um Operationen in linearen ver-ketteten Listen.
Widmayer Vereinfachtes Verfahren: Alle Elemente werden immer in Listen gespeichert. Der Hasheintrag ist nur Referenz auf Liste.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Die durchschnittliche Anzahl der Einträge in einer Kette ist gerade α = n / m, wenn n Einträge auf m Ketten verteilt sind.
Die Effizienz der erfolglosen Suche läßt sich verbessern, wenn man die Überlaufketten sortiert hält. Dann muß man beim erfolglosen Suchen nicht stets bis zum Listenende suchen, sondern kann im Mittel schon in der Mitte der Liste der Überläufer aufhören (man beachte, daß die erfolglose Suche dann für α ≤ 1 im Mittel schneller ist als die erfolgreiche).
Ein Belegungsfaktor von mehr als 1 ist möglich; d.h., selbst wenn die zu verwaltende Datenmenge mehr als vorgesehen wächst, so arbeitet das Verfahren noch korrekt.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Verkettung der Überläufer
Effizienz der Verkettung der Überläufer (Anzahl der durchschnittlichen
Die entscheidenden Nachteile der Methoden der Verkettung der Überläufer sind der Speicherplatzbedarf für die Zeiger und die Tatsache, daß selbst dann Platz für Überläufer außerhalb der Hashtabelle benötigt wird, wenn in der Hashtabelle noch viele Plätze frei sind.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
Im Unterschied zur Verkettung der Überläufer außerhalb der Hashtabelle versucht man bei offenen Hashverfahren, Überläufer in der Hashtabelle unterzubringen.
Wenn also beim Versuch, den Schlüssel k in die Hashtabelle an Position h(k) einzutragen, fest-gestellt wird, daß t[h(k)] bereits belegt ist, so muß man nach einer festen Regel einen anderen, nicht belegten Platz (eine offene Stelle) finden, an dem man k unterbringen kann.
Da man von vornherein nicht wissen kann, welche Plätze belegt sein werden und welche nicht, definiert man für jeden Schlüssel eine Reihenfolge, in der alle Speicher-plätze, und zwar einer nach dem anderen, betrachtet werden. Sobald ein betrachteter Platz frei ist, wird der Schlüssel dort gespeichert.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
Die Hauptaufgabe ist nun das Finden eine geeigneten und effizienten Sondierungsfolge und deren Berechnung.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
Sei s(j,k) eine Funktion von j und k so, daß (h(k)-s(j,k)) mod m für j = 0,1,..,m-1, eine Sondierungsfolge bildet, d.h. eine Permutation aller Hashadressen.
Suchen nach Schlüssel k: Beginne mit Hashadresse i = h (k). Solange k nicht in t[i] gespeichert ist und t[i] nicht frei ist, suche weiter bei i = (h(k)-s(j,k)) mod m, für aufsteigende Werte von j. Falls t[i] belegt ist, wurde k gefunden; sonst war die Suche erfolglos.
Einfügen eines Schlüssels k: Wir nehmen an, daß k nicht schon in t vorkommt (das kann durch eine Suche festgestellt werden). Beginne mit Hashadresse i = h(k). Solange t[i] belegt ist, mache weiter bei i = (h(k)-s(j,k)) mod m, für steigende Werte von j. Trage k bei t[i] ein.
Entfernen eines Schlüssels k: Suche nach Schlüssel k. Verläuft die Suche erfolgreich und ist i die Adresse, an der k gefunden wird, dann markiere t[i] als entfernt; sonst kommt k nicht in t vor und kann auch nicht entfernt werden.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
Prinzip des Sondierens
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
h(k),h(k)−1,h(k)−2,..,0,m−1,..,h(k)+1s(j,k)=j
Effizienz beim linearen Sondieren (α ist Belegungsfaktor)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
N=7; H=vector(N,-1)function hash(k,N) { return k % N }function probe(H,N,i) { i=i-1; n=N-1 while(n && H[i]!=-1) { n-- i=(i-1) % N } return n==0?-1:i}function search(H,N,k) { i=hash(k,N) if (H[i]==k) return i; i=i-1; n=N-1 while(n && H[i]!=k && H[i]!=-1) { n-- i=(i-1) % N } return n==0?-1:i }function collision(H,N,k) { i=hash(k,N) return H[i]!=-1}
Lineares Sondieren
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
h(k),h(k)+1,h(k)−1,h(k)+4,h(k)−4,..s(j,k)=⌊j2⌋2(−1)j
Effizienz beim qudratischen Sondieren (α ist Belegungsfaktor)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Offene Hashverfahren
Die Effizienz des uniformen Sondierens wird bereits annähernd erreicht, wenn man statt einer polynomiellen Permutation für die Sondierungsfolge eine zweite Hashfunktion verwendet; die gewählte Sondierungsfolge für Schlüssel k ist
h(k),h(k)−h'(k),h(k)−2h'(k),..,h(k)−(m−1)h'(k)s(j,k)=jh'(k)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul HS Hashtabellen und Überläufer :: Vertiefende Literatur