Nun, da std
eine echte Hash-Map in unordered_map
Hat, warum (oder wann) würde ich immer noch den guten alten map
über unordered_map
Auf Systemen verwenden wollen wo gibt es das eigentlich Gibt es offensichtliche Situationen, die ich nicht sofort sehen kann?
Wie bereits erwähnt , erlaubt map
das sortierte Durchlaufen der Elemente, unordered_map
Jedoch nicht. Dies ist in vielen Situationen sehr wichtig, beispielsweise beim Anzeigen einer Sammlung (z. B. eines Adressbuchs). Dies äußert sich auch auf andere indirekte Weise wie: (1) Starten Sie die Iteration von dem Iterator, der von find()
zurückgegeben wird, oder (2) Vorhandensein von Mitgliedsfunktionen wie lower_bound()
.
Ich denke auch, dass es einen Unterschied in der Worst-Case-Komplexität search gibt.
Für map
ist es O (lg N)
Für unordered_map
Ist es O (N) [Dies darf, wenn die Hash-Funktion nicht gut ist und zu zu vielen Hash-Kollisionen führt.]
Gleiches gilt für worst case Streichung Komplexität.
Zusätzlich zu den obigen Antworten sollten Sie auch beachten, dass nur weil unordered_map
Eine konstante Geschwindigkeit ist (O(1)
), dies nicht bedeutet, dass es schneller ist als map
(of order log(N)
). Die Konstante kann größer als log(N)
sein, zumal N
auf 2 begrenzt ist32 (oder 264).
Zusätzlich zu den anderen Antworten (map
behält Ordnung bei und Hash-Funktionen können schwierig sein) kann es sein, dass map
performanter ist.
Zum Beispiel in einem Programm, in dem ich für einen Blog-Beitrag lief , sah ich, dass für VS10 std::unordered_map
Langsamer war als std::map
( obwohl boost::unordered_map
schneller war als beide).
Beachten Sie den 3. bis 5. Takt.
Dies liegt an Googles Chandler Carruth in seinem CppCon 2014 Vortrag
std::map
ist (von vielen als nicht nützlich erachtet) für leistungsorientiertes Arbeiten: Wenn Sie einen O (1) -amortisierten Zugriff wünschen, verwenden Sie ein geeignetes assoziatives Array (oder mangels eines, std::unorderded_map
); Wenn Sie einen sortierten sequenziellen Zugriff wünschen, verwenden Sie etwas, das auf einem Vektor basiert.
Ebenfalls, std::map
ist ein ausgeglichener Baum; und man muss es unglaublich oft durchqueren oder neu ausbalancieren. Dies sind Cache-Killer- und Cache-Apokalypse-Operationen ... also sag einfach NEIN zu std::map
.
Vielleicht interessieren Sie sich für this SO question für effiziente Hash-Map-Implementierungen.
(PS - std::unordered_map
ist Cache-unfreundlich, da verknüpfte Listen als Buckets verwendet werden.)
Ich denke, es liegt auf der Hand, dass Sie den std::map
, Den Sie benötigen, verwenden, um Elemente in der Karte in sortierter Reihenfolge zu durchlaufen.
Sie können es auch verwenden, wenn Sie einen Vergleichsoperator (der intuitiv ist) anstelle einer Hash-Funktion (die im Allgemeinen sehr unintuitiv ist) schreiben möchten.
Angenommen, Sie haben sehr große Tasten, möglicherweise große Zeichenfolgen. Um einen Hash-Wert für eine große Zeichenfolge zu erstellen, müssen Sie die gesamte Zeichenfolge von Anfang bis Ende durchgehen. Es dauert mindestens eine lineare Zeit bis zur Länge des Schlüssels. Wenn Sie jedoch nur einen Binärbaum mit dem Operator >
Des Schlüssels durchsuchen, kann jeder Zeichenfolgenvergleich zurückgegeben werden, wenn die erste Nichtübereinstimmung gefunden wird. Dies ist normalerweise sehr früh für große Saiten.
Diese Argumentation kann auf die Funktion find
von std::unordered_map
Und std::map
Angewendet werden. Wenn die Art des Schlüssels so ist, dass es länger dauert, einen Hash zu erzeugen (im Fall von std::unordered_map
), Als um die Position eines Elements mit der binären Suche zu finden (im Fall von std::map
) sollte es schneller sein, einen Schlüssel im std::map
nachzuschlagen. Es ist ziemlich einfach, sich Szenarien vorzustellen, in denen dies der Fall wäre, aber ich glaube, dass sie in der Praxis ziemlich selten sind.