Antworten:
Sie werden auf sehr unterschiedliche Weise implementiert.
hash_map
(unordered_map
in TR1 und Boost; verwenden Sie diese stattdessen) Verwenden Sie eine Hash-Tabelle, in der der Schlüssel in einen Slot in der Tabelle gehasht und der Wert in einer mit diesem Schlüssel verknüpften Liste gespeichert wird.
map
wird als ausgeglichener binärer Suchbaum implementiert (normalerweise ein rot / schwarzer Baum).
A unordered_map
sollte eine etwas bessere Leistung für den Zugriff auf bekannte Elemente der Sammlung bieten, hat jedoch map
zusätzliche nützliche Eigenschaften (z. B. wird es in sortierter Reihenfolge gespeichert, die das Durchlaufen von Anfang bis Ende ermöglicht). unordered_map
wird beim Einfügen und Löschen schneller sein als a map
.
hash_map
war eine häufige Erweiterung, die von vielen Bibliotheksimplementierungen bereitgestellt wurde. Genau aus diesem Grund wurde es umbenannt, unordered_map
als es als Teil von TR1 zum C ++ - Standard hinzugefügt wurde. map wird im Allgemeinen mit einem ausgeglichenen Binärbaum wie einem rot-schwarzen Baum implementiert (Implementierungen variieren natürlich). hash_map
und unordered_map
werden im Allgemeinen mit Hash-Tabellen implementiert. Somit wird die Reihenfolge nicht eingehalten. unordered_map
Einfügen / Löschen / Abfragen ist O (1) (konstante Zeit), wobei Map O (log n) ist, wobei n die Anzahl der Elemente in der Datenstruktur ist. So unordered_map
geht es schneller, und wenn Sie sich nicht um die Reihenfolge der Artikel kümmern, sollten Sie es vorziehen map
. Manchmal möchten Sie die Reihenfolge aufrechterhalten (sortiert nach dem Schlüssel) und dafür map
wäre die Wahl.
Einige der Hauptunterschiede liegen in den Komplexitätsanforderungen.
A map
benötigt O(log(N))
Zeit für Einfügungen und Suchvorgänge, da es als Rot-Schwarz-Baum- Datenstruktur implementiert ist .
A unordered_map
benötigt eine 'durchschnittliche' Zeit O(1)
für Einfügungen und Fundstücke, darf jedoch eine Worst-Case-Zeit von haben O(N)
. Dies liegt daran, dass es mithilfe der Hash Table- Datenstruktur implementiert wird.
Normalerweise ist unordered_map
es also schneller, aber abhängig von den Tasten und der von Ihnen gespeicherten Hash-Funktion kann es viel schlimmer werden.
Die C ++ - Spezifikation gibt nicht genau an, welchen Algorithmus Sie für die STL-Container verwenden müssen. Es gibt jedoch bestimmte Einschränkungen für ihre Leistung, die die Verwendung von Hash-Tabellen für ausschließenmap
und andere assoziative Container ausschließen. (Sie werden am häufigsten mit rot / schwarzen Bäumen implementiert.) Diese Einschränkungen erfordern für diese Container eine bessere Leistung im ungünstigsten Fall, als Hash-Tabellen liefern können.
Viele Leute wollen jedoch wirklich Hash-Tabellen, daher sind Hash-basierte STL-assoziative Container seit Jahren eine häufige Erweiterung. Folglich fügten sie unordered_map
und so zu späteren Versionen des C ++ - Standards hinzu.
map
im Allgemeinen ein ausgewogener Baum ist, der operator<()
als Mittel zur Standortbestimmung verwendet wird.
map
wird implementiert von balanced binary search tree
(normalerweise a rb_tree
), da alle Mitglieder in balanced binary search tree
sortiert sind, so ist map;
hash_map
wird von. implementiert, hashtable
da alle Mitglieder in hashtable
unsortiert sind, sodass die Mitglieder in hash_map(unordered_map)
nicht sortiert sind.
hash_map
ist keine C ++ - Standardbibliothek, aber jetzt wurde sie in unordered_map
(Sie können sich vorstellen, dass sie umbenannt wurde) umbenannt und wird in C ++ - Standardbibliothek, da C ++ 11 diese Frage sieht. Unterschied zwischen hash_map und unordered_map?für mehr Details.
Im Folgenden werde ich eine Kernschnittstelle aus dem Quellcode geben, wie die Karte mit zwei Typen implementiert ist.
Der folgende Code soll nur zeigen, dass Map nur ein Wrapper von balanced binary search tree
ist. Fast alles, was seine Funktion ist, ist nur das Aufrufen der balanced binary search tree
Funktion.
template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
// used for rb_tree to sort
typedef Key key_type;
// rb_tree node value
typedef std::pair<key_type, value_type> value_type;
typedef Compare key_compare;
// as to map, Key is used for sort, Value used for store value
typedef rb_tree<key_type, value_type, key_compare> rep_type;
// the only member value of map (it's rb_tree)
rep_type t;
};
// one construct function
template<typename InputIterator>
map(InputIterator first, InputIterator last):t(Compare()){
// use rb_tree to insert value(just insert unique value)
t.insert_unique(first, last);
}
// insert function, just use tb_tree insert_unique function
//and only insert unique value
//rb_tree insertion time is : log(n)+rebalance
// so map's insertion time is also : log(n)+rebalance
typedef typename rep_type::const_iterator iterator;
std::pair<iterator, bool> insert(const value_type& v){
return t.insert_unique(v);
};
hash_map
::hash_map
wird implementiert, hashtable
dessen Struktur ungefähr so ist:
Im folgenden Code werde ich den Hauptteil von geben hashtable
und dann geben hash_map
.
// used for node list
template<typename T>
struct __hashtable_node{
T val;
__hashtable_node* next;
};
template<typename Key, typename Value, typename HashFun>
class hashtable{
public:
typedef size_t size_type;
typedef HashFun hasher;
typedef Value value_type;
typedef Key key_type;
public:
typedef __hashtable_node<value_type> node;
// member data is buckets array(node* array)
std::vector<node*> buckets;
size_type num_elements;
public:
// insert only unique value
std::pair<iterator, bool> insert_unique(const value_type& obj);
};
Wie map's
nur ein Mitglied ist rb_tree
, ist das hash_map's
einzige Mitglied hashtable
. Es ist der Hauptcode wie folgt:
template<typename Key, typename Value, class HashFun = std::hash<Key>>
class hash_map{
private:
typedef hashtable<Key, Value, HashFun> ht;
// member data is hash_table
ht rep;
public:
// 100 buckets by default
// it may not be 100(in this just for simplify)
hash_map():rep(100){};
// like the above map's insert function just invoke rb_tree unique function
// hash_map, insert function just invoke hashtable's unique insert function
std::pair<iterator, bool> insert(const Value& v){
return t.insert_unique(v);
};
};
Das folgende Bild zeigt, wenn eine hash_map 53 Buckets hat und einige Werte einfügt, ihre interne Struktur.
Das folgende Bild zeigt einen Unterschied zwischen map und hash_map (unordered_map). Das Bild stammt von Wie wähle ich zwischen map und unordered_map ? ::
Ich weiß nicht, was es gibt, aber hash_map benötigt mehr als 20 Sekunden, um () 150K vorzeichenlose Ganzzahlschlüssel und Float-Werte zu löschen. Ich laufe nur und lese den Code eines anderen.
So enthält es hash_map.
#include "StdAfx.h"
#include <hash_map>
Ich habe dies hier gelesen https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap
zu sagen, dass clear () die Ordnung von O (N) ist. Das ist für mich sehr seltsam, aber so ist es nun mal.