Ich möchte eine Hash-Tabelle mithilfe von binären Suchbäumen implementieren, um die Suchkomplexität im Prozess der getrennten Verkettung von O (n) (mithilfe einer verknüpften Liste) auf O (Protokoll n) (mithilfe von BST) zu reduzieren. Kann das gemacht werden und wenn ja, wie? Es wäre einfacher zu verstehen, ob die Lösung Schritt für Schritt die Implementierung der Logik ist.
Ich möchte die Suchzeit in der Hashtabelle reduzieren (Build mit separater Verkettung), aber gleichzeitig möchte ich nicht, dass sich die Einfügezeit erhöht. Für mein Projekt kann ich die Hash-Funktion nicht ändern, um Kollisionen zu reduzieren. Aufgrund der Skalierbarkeit kommt es jedoch zu Kollisionen. Ich versuche, eine Lösung zu finden, damit ich im Falle einer Kollision irgendwie mit der besten Zugriffs- und Einfügezeit arbeiten kann ... dh um den aktuellen Status zu verwalten, als den gesamten Algorithmus neu zu strukturieren. Wenn es nicht klappt, muss es umstrukturiert werden. Also irgendwelche Ideen?
Antworten:
Was Sie verlangen, ist aufgrund Ihrer Einschränkungen möglich.
Analyse
Die Stärke einer Hash-Tabelle liegt in ihrer schnellen Suche und Einfügegeschwindigkeit. Um diese Geschwindigkeit zu erreichen, muss man jeden Anschein von Ordnung in der Tabelle aufgeben: dh alle Einträge sind durcheinander. Es ist akzeptabel, eine Liste als Tabelleneintrag zu verwenden, da die Listen, während die Durchquerung O (n) ist, dazu neigen, kurz zu sein, vorausgesetzt, die Hash-Tabelle ist ausreichend groß und die in der Tabelle gespeicherten Objekte werden unter Verwendung eines Hash-Algorithmus guter Qualität gehasht.
Ein binärer Suchbaum (BST) hat eine schnelle Einfügung und Suche bei O (log 2 n). Außerdem werden die gespeicherten Elemente eingeschränkt: Es muss eine Möglichkeit geben, die Elemente zu ordnen. Bei zwei im Baum gespeicherten Elementen A und B muss festgestellt werden können, ob A vor B steht oder ob sie eine äquivalente Reihenfolge haben.
Eine Hash-Tabelle unterliegt keiner solchen Einschränkung: Elemente in einer Hash-Tabelle müssen zwei Eigenschaften haben. Erstens muss es eine Möglichkeit geben, festzustellen, ob sie gleichwertig sind. Zweitens muss es eine Möglichkeit geben, einen deterministischen Hash-Code zu berechnen. Bestellung ist keine Voraussetzung.
Wenn Ihre Hash-Tabellenelemente eine Reihenfolge haben, können Sie eine BST als Hash-Tabelleneintrag verwenden, um Objekte mit demselben Hash-Code (Kollisionen) zu speichern. Aufgrund einer BST mit O (log 2 n) -Suche und Einfügung ist der schlechteste Fall für die gesamte Struktur (Hash-Tabelle plus BST) jedoch technisch besser als die Verwendung einer Liste als Tabelleneintrag. Abhängig von der BST-Implementierung wird mehr Speicher als eine Liste benötigt, aber wahrscheinlich nicht viel mehr.
Bitte beachten Sie, dass der Overhead und das Verhalten eines BST in realen Situationen normalerweise nichts als Hash-Tabellen-Buckets auf den Tisch bringen , weshalb die theoretisch schlechte Leistung einer Liste akzeptabel ist. Mit anderen Worten, die Hash-Tabelle gleicht die Schwäche der Liste aus, indem weniger Elemente in jede Liste (Bucket) eingefügt werden. Das Problem stellte jedoch ausdrücklich fest, dass die Hash-Tabelle nicht größer werden kann und Kollisionen häufiger auftreten als in einer Hash-Tabelle üblich.
Implementierung
Ich werde hier keinen Code einfügen, weil es ehrlich gesagt nicht wirklich notwendig ist und Sie sowieso keine Sprache angegeben haben.
Ich würde einfach die Standard-Hash-Tabelle, die die Standardbibliothek Ihrer Sprache enthält, in eine neue Klasse kopieren und dann den Tabellen-Bucket-Typ von einer Liste in einen Baum ändern. Abhängig von der Sprache und der Standardbibliothek kann dies sehr trivial sein.
Normalerweise würde ich das Kopieren und Einfügen einer solchen Codierung nicht befürworten. Es ist jedoch eine einfache Möglichkeit, sehr schnell eine kampferprobte Datenstruktur zu erhalten .
quelle
Die Verwendung eines Binärbaums für die Kollisionsbehandlung in einer Hash-Tabelle ist nicht nur möglich, sondern wurde bereits durchgeführt.
Walter Bright ist am besten als Erfinder der Programmiersprache D bekannt , hat aber auch eine ECMAScript-Variante namens DMDScript geschrieben . In der Vergangenheit war eine Schlagzeile von DMDScript (oder möglicherweise eines Vorfahren - ich erinnere mich an den Namen DScript), dass seine Hashtabellen dazu neigten, die in vielen ähnlichen Sprachen zu übertreffen. Der Grund - Kollisionsbehandlung mit Binärbäumen.
Ich erinnere mich nicht genau, woher das kommt, aber die verwendeten Bäume waren naive Binärbäume ohne partielles Ausgleichsschema (nicht AVL, rot-schwarz oder was auch immer), was sinnvoll ist, wenn man annimmt, dass die Größe der Hashtabelle selbst geändert wird, wenn sie überfüllt wird und Sie erhalten keine absurd unwahrscheinlichen Raten von Hash-Kollisionen, die Binärbäume sollten immer klein sein. Grundsätzlich ist der schlimmste Fall immer noch derselbe wie die Verwendung einer verknüpften Liste für die Kollisionsbehandlung (außer Sie zahlen den Preis für zwei Zeiger pro Knoten anstelle von einem), aber der durchschnittliche Fall reduziert den Suchaufwand in jedem Hash-Bucket.
quelle