Ich sehe, wie Sie per Schlüssel auf Ihre Sammlung zugreifen können. Die Hash-Funktion selbst hat jedoch viele Operationen hinter den Kulissen, nicht wahr?
Vorausgesetzt, Sie haben eine nette Hash-Funktion, die sehr effizient ist, kann es dennoch viele Operationen erfordern.
Kann das erklärt werden?
c#
dictionary
hashtable
big-o
monogate
quelle
quelle
the growth
Komplexität mit verschiedenen Eingaben zu messen . Es geht nicht darum, wie viele Operationen Sie haben. Beispiel: Mit 1 Wert haben Siex
Sekunden, mitn
Werten benötigen Sieroughly
x*n
Sekunden => O (n).x
könnte viele Operationen zusammen sein.Antworten:
Das ist sicherlich wahr. Die Anzahl dieser Operationen hängt jedoch von der Größe des Schlüssels ab , nicht von der Größe der Hash-Tabelle, in die der Schlüssel eingefügt wird: Die Anzahl der Operationen zur Berechnung der Hash-Funktion ist für einen Schlüssel in einer Tabelle mit zehn oder gleich mit zehntausend Einträgen.
Aus diesem Grund wird der Aufruf der Hash-Funktion häufig als O (1) betrachtet. Dies funktioniert gut für Schlüssel mit fester Größe (Integralwerte und Zeichenfolgen mit fester Länge). Es bietet auch eine anständige Annäherung für Tasten mit variabler Größe und einer praktischen Obergrenze.
Im Allgemeinen
k
beträgt die Zugriffszeit einer Hash-Tabelle jedoch O (k), wobei die Obergrenze für die Größe des Hash-Schlüssels liegt.quelle
n
unterschiedlichen Elementen zu haben, wenn nicht mindestens ein Element durch mindestenslog(n)
Bits dargestellt wird.the number of these operations depends on the size of the key
und auf die Größe der gehashten Daten.k
muss keine Obergrenze sein. Die Suchzeit ist in der Schlüsselgröße linear , also ist es tatsächlich dort,O(k)
wok
die Schlüsselgröße ist. Wennk
es als Obergrenze verstanden wird, dann ist es tatsächlichO(1)
.O(1)
bedeutet nicht sofort.O(1)
bedeutet konstant ohne Rücksicht auf die Größe der Daten . Die Hash-Funktion benötigt eine bestimmte Zeit, aber diese Zeit skaliert nicht mit der Größe der Sammlung.quelle
GetHashCode()
, um die Hash-Codes der Elemente auf irgendeine Weise zu kombinieren. Wenn ich eine solche Klasse für eine erste Implementierung implementieren würde, würde ichGetHashCode()
genau so implementieren . Das würde ich natürlich auch später ändern.Unabhängig von der Größe Ihrer Sammlung dauert das Abrufen eines Mitglieds fast genauso lange.
Mit anderen Worten, ein Wörterbuch mit 5 Mitgliedern benötigt etwa 0,002 ms, um auf eines von ihnen zuzugreifen, und ein Wörterbuch mit 25 Mitgliedern sollte etwas Ähnliches benötigen. Big O bedeutet algorithmische Komplexität über die Sammlungsgröße anstelle der tatsächlich ausgeführten Anweisungen oder Funktionen
quelle
Wenn ein Wörterbuch / eine Karte als implementiert ist
HashMap
, hat es eine Best-Case-Komplexität vonO(1)
, da es im besten Fall genau die Berechnung des Hash-Codes des Schlüsselelements zum Abrufen erfordert, wenn keine Schlüsselkollisionen vorliegen.Eine Hash-Karte kann eine Worst-Case - Laufzeitkomplexität von
O(n)
wenn Sie eine Menge von Schlüsselkollisionen oder eine sehr schlechten Hash - Funktion, da es in diesem Fall zu einer linearen Abtastung des gesamten Arrays abbaut , die die Daten enthalten.Bedeutet
O(1)
auch nicht sofort , es bedeutet, dass es eine konstante Menge hat. Die Auswahl der richtigen Implementierung für ein Wörterbuch kann also auch von der Anzahl der Elemente in der Sammlung abhängen, da sehr hohe konstante Kosten für die Funktion viel schlimmer sind, wenn nur wenige Einträge vorhanden sind.Aus diesem Grund werden Wörterbücher / Karten für verschiedene Szenarien unterschiedlich implementiert. Für Java gibt es mehrere verschiedene Implementierungen, C ++ verwendet Rot- / Schwarzbäume usw. Sie haben sie basierend auf der Anzahl der Daten und basierend auf ihrer besten / durchschnittlichen / schlechtesten Laufzeiteffizienz ausgewählt.
quelle
HashMap
auf einen ausgeglichenen Baum zurück, falls mehrere Kollisionen erkannt werden.Theoretisch ist es immer noch O (n), da im schlimmsten Fall alle Ihre Daten identischen Hash haben und zusammengebündelt werden. In diesem Fall müssen Sie alles linear durchlaufen.
quelle
Siehe Beitrag Was bedeutet "O (1) Zugriffszeit"?
Die Anzahl der Operationen in einer Hash-Funktion ist irrelevant, solange für JEDES Element in der Sammlung dieselbe (konstante) Zeit benötigt wird. Der Zugriff auf ein Element in einer Sammlung von 2 Elementen dauert beispielsweise 0,001 ms, aber auch der Zugriff auf ein Element in einer Sammlung von 2.000.000.000 Elementen dauert 0,001 ms. Obwohl die Hash-Funktion Hunderte von if-Anweisungen und mehrere Berechnungen enthalten kann.
quelle
aus den Dokumenten:
Es kann also O (1) sein, ist aber möglicherweise langsamer. Hier finden Sie einen weiteren Thread zur Leistung von Hashtabellen: Hash-Tabelle - warum ist sie schneller als Arrays?
quelle
Wenn Sie die Tatsache berücksichtigen, dass immer größere Wörterbücher mehr Speicherplatz beanspruchen, die Cache-Hierarchie weiter unten durchlaufen und schließlich den Speicherplatz auf der Festplatte verlangsamen, ist es schwer zu argumentieren, dass es sich wirklich um O (1) handelt. Die Leistung des Wörterbuchs wird langsamer, wenn es größer wird, was wahrscheinlich zu einer zeitlichen Komplexität von O (log N) führt. Glaubst du mir nicht? Probieren Sie es selbst mit 1, 100, 1000, 10000 usw. Wörterbuchelementen aus, bis zu 100 Milliarden, und messen Sie, wie lange es in der Praxis dauert, ein Element nachzuschlagen.
Wenn Sie jedoch vereinfachend davon ausgehen, dass der gesamte Speicher in Ihrem System ein Direktzugriffsspeicher ist und in konstanter Zeit zugegriffen werden kann, können Sie behaupten, dass das Wörterbuch O (1) ist. Diese Annahme ist weit verbreitet, obwohl sie für keinen Computer mit Festplatten-Swap-Speicher wirklich zutrifft und angesichts der verschiedenen Ebenen des CPU-Cache auf jeden Fall ziemlich umstritten ist.
quelle