Ich habe in meinen Abschlussklassen gehört, dass a HashTable
einen neuen Eintrag in den 'nächsten verfügbaren' Bucket legt, wenn der neue Schlüsseleintrag mit einem anderen kollidiert.
Wie würde der HashTable
immer noch den korrekten Wert zurückgeben, wenn diese Kollision auftritt, wenn mit dem Kollisionsschlüssel ein Rückruf angefordert wird?
Ich gehe davon aus, dass der Typ Keys
are String
und der hashCode()
von Java generierte Standardwert zurückgegeben werden.
Welche Strategien gibt es für den Umgang mit Kollisionen, wenn ich meine eigene Hashing-Funktion implementiere und sie als Teil einer Nachschlagetabelle (dh a HashMap
oder Dictionary
) verwende?
Ich habe sogar Notizen zu Primzahlen gesehen! Informationen aus der Google-Suche nicht so klar.
Wenn Sie über "Hash-Tabelle wird einen neuen Eintrag in den 'nächsten verfügbaren' Bucket platzieren, wenn der neue Schlüsseleintrag mit einem anderen kollidiert." Gesprochen haben, sprechen Sie über die offene Adressierungsstrategie der Kollisionsauflösung von Hash-Tabellen.
Es gibt verschiedene Strategien für Hash-Tabellen, um Kollisionen aufzulösen.
Die erste Art einer großen Methode erfordert, dass die Schlüssel (oder Zeiger auf sie) zusammen mit den zugehörigen Werten in der Tabelle gespeichert werden. Dazu gehören außerdem:
Eine weitere wichtige Methode zur Behandlung von Kollisionen ist die dynamische Größenänderung , die verschiedene Möglichkeiten bietet:
BEARBEITEN : Die oben genannten Informationen stammen aus wiki_hash_table , wo Sie nachsehen sollten, um weitere Informationen zu erhalten.
quelle
Für die Behandlung von Kollisionen stehen mehrere Techniken zur Verfügung. Ich werde einige von ihnen erklären
Verkettung: Bei der Verkettung verwenden wir Array-Indizes, um die Werte zu speichern. Wenn der Hashcode des zweiten Werts ebenfalls auf denselben Index verweist, ersetzen wir diesen Indexwert durch eine verknüpfte Liste, und alle Werte, die auf diesen Index verweisen, werden in der verknüpften Liste gespeichert, und der tatsächliche Array-Index zeigt auf den Kopf der verknüpften Liste. Wenn jedoch nur ein Hashcode auf einen Array-Index verweist, wird der Wert direkt in diesem Index gespeichert. Dieselbe Logik wird beim Abrufen der Werte angewendet. Dies wird in Java HashMap / Hashtable verwendet, um Kollisionen zu vermeiden.
Lineare Prüfung: Diese Technik wird verwendet, wenn die Tabelle mehr Index enthält als die zu speichernden Werte. Die lineare Sondiertechnik arbeitet mit dem Konzept, so lange zu erhöhen, bis Sie einen leeren Steckplatz finden. Der Pseudocode sieht folgendermaßen aus:
Double-Hashing-Technik: In dieser Technik verwenden wir zwei Hashing-Funktionen h1 (k) und h2 (k). Wenn der Schlitz bei h1 (k) belegt ist, wird die zweite Hashing-Funktion h2 (k) verwendet, um den Index zu erhöhen. Der Pseudocode sieht folgendermaßen aus:
Lineare Abtast- und Doppel-Hashing-Techniken sind Teil der offenen Adressierungstechnik und können nur verwendet werden, wenn die verfügbaren Slots mehr als die Anzahl der hinzuzufügenden Elemente sind. Es benötigt weniger Speicher als Verkettung, da hier keine zusätzliche Struktur verwendet wird, aber es ist langsam, weil viel Bewegung stattfindet, bis wir einen leeren Steckplatz finden. Auch in der offenen Adressierungstechnik setzen wir einen Grabstein, wenn ein Element aus einem Steckplatz entfernt wird, um anzuzeigen, dass das Element von hier entfernt wurde, weshalb es leer ist.
Weitere Informationen finden Sie auf dieser Website .
quelle
Ich empfehle Ihnen dringend, diesen Blog-Beitrag zu lesen, der kürzlich auf HackerNews veröffentlicht wurde: Wie HashMap in Java funktioniert
Kurz gesagt, die Antwort lautet
quelle
Dies gilt zumindest für das Oracle JDK nicht (es handelt sich um ein Implementierungsdetail, das zwischen verschiedenen Implementierungen der API variieren kann). Stattdessen enthält jeder Bucket eine verknüpfte Liste von Einträgen vor Java 8 und einen ausgeglichenen Baum in Java 8 oder höher.
Es verwendet das
equals()
, um den tatsächlich passenden Eintrag zu finden.Es gibt verschiedene Kollisionsbehandlungsstrategien mit unterschiedlichen Vor- und Nachteilen. Der Eintrag von Wikipedia in Hash-Tabellen gibt einen guten Überblick.
quelle
Hashtable
undHashMap
in jdk 1.6.0_22 von Sun / Oracle.public V get(Object key)
(gleiche Version wie oben). Wenn Sie eine genaue Version finden, in der diese verknüpften Listen angezeigt werden, würde mich das interessieren.Entry
Objekten zu iterieren :localEntry = localEntry.next
e = e.next
nicht++index
. +1Update seit Java 8: Java 8 verwendet einen selbstausgeglichenen Baum für die Kollisionsbehandlung, wodurch der Worst-Case für die Suche von O (n) auf O (log n) verbessert wird. Die Verwendung eines selbstausgeglichenen Baums wurde in Java 8 als Verbesserung gegenüber der Verkettung (verwendet bis Java 7) eingeführt, die eine verknüpfte Liste verwendet und einen Worst-Case von O (n) für die Suche aufweist (da diese durchlaufen werden muss) Die Liste)
Um den zweiten Teil Ihrer Frage zu beantworten, erfolgt das Einfügen durch Zuordnen eines bestimmten Elements zu einem bestimmten Index im zugrunde liegenden Array der Hashmap. Wenn jedoch eine Kollision auftritt, müssen alle Elemente weiterhin beibehalten (in einer sekundären Datenstruktur gespeichert) werden und nicht nur im zugrunde liegenden Array ersetzt). Dies erfolgt normalerweise, indem jede Array-Komponente (Slot) zu einer sekundären Datenstruktur (auch bekannt als Bucket) gemacht wird und das Element dem Bucket hinzugefügt wird, das sich auf dem angegebenen Array-Index befindet (falls der Schlüssel noch nicht im Bucket vorhanden ist, in in diesem Fall wird es ersetzt).
Während der Suche wird der Schlüssel auf den entsprechenden Array-Index gehasht und nach einem Element gesucht, das mit dem (genauen) Schlüssel im angegebenen Bucket übereinstimmt. Da der Bucket keine Kollisionen verarbeiten muss (Schlüssel direkt vergleicht), wird das Problem der Kollisionen gelöst, jedoch auf Kosten der Einfügung und Suche in der sekundären Datenstruktur. Der entscheidende Punkt ist, dass in einer Hashmap sowohl der Schlüssel als auch der Wert gespeichert werden. Selbst wenn der Hash kollidiert, werden die Schlüssel direkt auf Gleichheit (im Bucket) verglichen und können somit im Bucket eindeutig identifiziert werden.
Die Kollisionsbehandlung bringt die schlechteste Leistung beim Einfügen und Nachschlagen von O (1), wenn keine Kollisionsbehandlung erfolgt, zu O (n) zur Verkettung (eine verknüpfte Liste wird als sekundäre Datenstruktur verwendet) und O (log n). für selbstausgeglichenen Baum.
Verweise:
quelle
Mit der Methode equals wird überprüft, ob der Schlüssel gerade vorhanden ist, insbesondere, wenn sich mehr als ein Element im selben Bucket befindet.
quelle
Da es einige Unklarheiten darüber gibt, welchen Algorithmus Javas HashMap verwendet (in der Sun / Oracle / OpenJDK-Implementierung), hier die relevanten Quellcode-Schnipsel (aus OpenJDK, 1.6.0_20, unter Ubuntu):
Diese Methode (zitieren ist von Linien 355-371) aufgerufen wird , wenn ein Eintrag in der Tabelle nach oben, zum Beispiel aus
get()
,containsKey()
und einige andere. Die for-Schleife durchläuft hier die verknüpfte Liste, die von den Eingabeobjekten gebildet wird.Hier der Code für die Eingabeobjekte (Zeilen 691-705 + 759):
Gleich danach kommt die
addEntry()
Methode:Dadurch wird der neue Eintrag auf der Vorderseite des Buckets mit einem Link zum alten ersten Eintrag hinzugefügt (oder null, falls kein solcher vorhanden ist). In ähnlicher
removeEntryForKey()
Weise geht die Methode die Liste durch und sorgt dafür, dass nur ein Eintrag gelöscht wird, wobei der Rest der Liste intakt bleibt.Hier ist also eine verknüpfte Eintragsliste für jeden Bucket, und ich bezweifle sehr, dass sich dies von
_20
zu geändert hat_22
, da es ab 1.2 so war.(Dieser Code ist (c) 1997-2007 Sun Microsystems und unter GPL verfügbar. Verwenden Sie zum besseren Kopieren jedoch die Originaldatei, die in src.zip in jedem JDK von Sun / Oracle und auch in OpenJDK enthalten ist.)
quelle
Hier ist eine sehr einfache Implementierung der Hash-Tabelle in Java. in nur implementiert
put()
undget()
, aber Sie können einfach hinzufügen, was Sie möchten. Es basiert auf der Java-hashCode()
Methode, die von allen Objekten implementiert wird. Sie könnten leicht Ihre eigene Schnittstelle erstellen,und erzwingen Sie die Implementierung durch die Schlüssel, wenn Sie möchten.
quelle
Es gibt verschiedene Methoden zur Kollisionsauflösung. Einige davon sind separate Verkettung, offene Adressierung, Robin Hood-Hashing, Kuckuck-Hashing usw.
Java verwendet die separate Verkettung zum Auflösen von Kollisionen in Hash-Tabellen. Hier finden Sie einen guten Link dazu: http://javapapers.com/core-java/java-hashtable/
quelle