Hashtail-Kollision rehashing - Wie werden Werte gelesen?

8

Ich versuche zu verstehen, wie Hashtables in C # funktionieren. Ich lese den MSDN-Artikel und ich verstehe, dass C # Hashtables 'rehashing' für Kollisionen verwenden, dh wenn ich versuche, ein Schlüssel / Wert-Paar in die Hashtabelle einzufügen, wenn HashFunction H1 zu einer Kollision führt, wird es HashFunction H2, H3 versuchen usw., bis keine Kollisionen gefunden werden.

MSDN Zitat:

  

Die Hashtable-Klasse verwendet eine andere Technik, die als bezeichnet wird   Rehasing. (Einige Quellen beziehen sich auf das Wiederhashing als doppeltes Hashing.)

     

Das Umstellen funktioniert wie folgt: Es gibt verschiedene Hash-Werte   Funktionen, H1 ... Hn, und beim Einfügen oder Abrufen eines Elements aus   In der Hash-Tabelle wird zunächst die H1-Hash-Funktion verwendet. Wenn das dazu führt   Bei einer Kollision wird stattdessen H2 und bei Bedarf bis zu Hn versucht.   Der vorherige Abschnitt zeigte nur eine Hash-Funktion, nämlich die   Anfangs-Hash-Funktion (H1). Die anderen Hash-Funktionen sind sehr ähnlich   zu dieser Funktion, nur differenzierend um einen multiplikativen Faktor. Im   Allgemein wird die Hash-Funktion Hk wie folgt definiert:

     

Hk (Schlüssel) = [GetHash (Schlüssel) + k * (1 + (((GetHash (Schlüssel) & gt; & gt; 5) + 1)%   (hashsize - 1)))]% hashsize

Nehmen Sie jedoch das Beispiel von der MSDN-Site1:

%Vor%

Nehmen wir an, dass das Hinzufügen des zweiten Schlüssels zu einer Kollision führt, also muss H2 verwendet werden. Wenn ich jedoch Mitarbeiter anrufe ["222-33-4444"], wie kann die Hashtabelle H2 verwenden? Gibt es eine separate Zuordnung? Danke.

    
user981225 06.02.2012, 20:49
quelle

3 Antworten

3

Hash-Tabellen speichern sowohl den Schlüssel als auch den Wert in der Hash-Tabelle selbst. Auf diese Weise kann später während Operationen wie Hash-Table-Look-Ups garantiert werden, dass der gefundene Wert derjenige ist, der mit dem für die Suche verwendeten Index übereinstimmt. Hash-Tabellen verwenden eine einfache "versuchen Sie die grundlegende Methode der Suche nach Erfolg bis zum Erfolg" -Methode. In diesem Fall ist die Methode der Suche "Verwenden Sie die Hash-Funktion X", wobei sich X bei einem Fehler ändert.

In anderen Schemata ist das Nachschlageverfahren "schaue auf den Tabelleneintrag X" (wie durch eine Hash-Funktion bestimmt), wobei X jeden Fehler einfach um eins erhöht.

Die quälende Frage ist nun, was passiert, wenn der Wert NICHT in der Tabelle ist? Nun, das kann ziemlich hässlich sein: Wenn Sie entweder einen Eintrag in der Tabelle, der fehlt, getroffen haben oder, noch schlimmer, wenn Sie so viele Einträge durchlaufen haben, wie in der Tabelle gespeichert sind, können Sie sicher sein, dass der Eintrag isn ist 't there - aber das kann im schlimmsten Fall "eine Weile" dauern.

Beachten Sie, dass nur ein Wert mit einem Schlüssel verknüpft werden kann. Sobald Sie den Schlüssel gefunden haben, haben Sie den Wert gefunden. Das Schlimmste, was eine Hash-Tabelle tun kann, ist das Äquivalent einer cache-unfreundlichen linearen Suche über alle Werte in der Hash-Tabelle selbst ... aber schließlich findet sie den Wert, wenn sie da ist, weil sie den gespeicherten Schlüssel vergleicht der angeforderte Schlüssel, um zu testen, ob es da ist. Die einzige Optimierung geschlossen Hash-Tabellen machen ist, wo zuerst - in diesem Fall, wo Hash-Funktion 1 sagt, und dann 2, und dann 3 ...

    
Kaganar 06.02.2012, 21:02
quelle
1

Ich glaube, du verstehst das Missverständnis falsch. Es gibt nur eine Hash-Funktion: das virtuelle object.GetHashCode() (oder, wenn Sie einen IHashCodeProvider oder IEqualityComparer angeben, verwendet es dieses Objekt, um den Hash-Code zu berechnen). Wenn die Hash-Tabelle voll ist, erweitert sie ihre Kapazität und verteilt die Elemente neu über die neuen, größeren Arrays. Die private Methode, die dies tut, heißt Rehash() , berechnet aber Hash-Codes nicht neu.

KORREKTUR

Das Umladen verwendet keine neue Funktion, sondern arbeitet mit dem vorhergehenden Wert des Hash-Codes; Dies hat den Effekt, dass nachfolgende Slots durchsucht werden, bis ein leeres gefunden wird (für insert / set) oder bis alle Schlüssel mit dem gleichen (initialen) Hash-Code auf Gleichheit mit dem Index-Schlüssel überprüft wurden (zum Abrufen).

BEARBEITEN

Um Ihre Frage direkt zu beantworten:

  

Nehmen wir an, dass das Hinzufügen des zweiten Schlüssels zu einer Kollision führt, also muss H2 verwendet werden. Wenn ich jedoch Mitarbeiter anrufe ["222-33-4444"], wie kann die Hashtabelle H2 verwenden? Gibt es eine separate Zuordnung? Danke.

  1. Berechne den richtigen Bucket basierend auf dem Hash-Code des übergebenen Schlüssels.
  2. Wenn dieser Bucket leer ist, scheitern.
  3. Wenn der Schlüssel des Buckets mit dem übergebenen Schlüssel übereinstimmt, geben Sie den Wert des Buckets zurück.
  4. Wenn die Anzahl der Hash-Kollisionen null ist, schlagen Sie fehl.
  5. Berechnen Sie den nächsten Hash-Code aus dem aktuellen Hash-Code.
  6. Berechne den richtigen Bucket basierend auf dem neuen Hash-Code.
  7. Gehen Sie zu Schritt 2.
phoog 06.02.2012 20:58
quelle
0

Es wird zuerst H1 versuchen. Wenn keine Übereinstimmung gefunden wird, wird H2 verwendet. Und so weiter.

    
usr 06.02.2012 20:52
quelle

Tags und Links