Risposte:
Sono implementati in modi molto diversi.
hash_map
( unordered_map
in TR1 e Boost; usa invece quelli) usa una tabella hash in cui la chiave è sottoposta ad hashing in uno slot nella tabella e il valore è memorizzato in un elenco legato a quella chiave.
map
è implementato come un albero di ricerca binario bilanciato (di solito un albero rosso / nero).
An unordered_map
dovrebbe fornire prestazioni leggermente migliori per accedere agli elementi noti della raccolta, ma map
avrà caratteristiche utili aggiuntive (ad esempio, è memorizzato in ordine ordinato, che consente l'attraversamento dall'inizio alla fine). unordered_map
sarà più veloce durante l'inserimento e l'eliminazione di un file map
.
hash_map
era un'estensione comune fornita da molte implementazioni di librerie. Questo è esattamente il motivo per cui è stato rinominato unordered_map
quando è stato aggiunto allo standard C ++ come parte di TR1. map è generalmente implementato con un albero binario bilanciato come un albero rosso-nero (le implementazioni variano ovviamente). hash_map
e unordered_map
sono generalmente implementati con tabelle hash. Pertanto l'ordine non viene mantenuto. unordered_map
insert / delete / query sarà O (1) (tempo costante) dove map sarà O (log n) dove n è il numero di elementi nella struttura dati. Quindi unordered_map
è più veloce e se non ti interessa l'ordine degli articoli dovrebbe essere preferito map
. A volte vuoi mantenere l'ordine (ordinato dalla chiave) e per questo map
sarebbe la scelta.
Alcune delle differenze principali risiedono nei requisiti di complessità.
A map
richiede O(log(N))
tempo per le operazioni di inserimento e ricerca, poiché è implementato come una struttura dati ad albero rosso-nero .
An unordered_map
richiede un tempo "medio" di O(1)
per inserti e ritrovamenti, ma può avere un tempo nel caso peggiore di O(N)
. Questo perché è implementato utilizzando la struttura dati della tabella hash .
Quindi, di solito, unordered_map
sarà più veloce, ma a seconda dei tasti e della funzione hash che memorizzi, può diventare molto peggio.
La specifica C ++ non dice esattamente quale algoritmo devi usare per i contenitori STL. Tuttavia, pone alcuni vincoli alle loro prestazioni, il che esclude l'uso di tabelle hash map
e altri contenitori associativi. (Sono più comunemente implementati con alberi rosso / nero.) Questi vincoli richiedono prestazioni nel caso peggiore per questi contenitori migliori di quelle che le tabelle hash possono fornire.
Molte persone vogliono davvero le tabelle hash, tuttavia, i contenitori associativi STL basati su hash sono stati un'estensione comune da anni. Di conseguenza, hanno aggiunto unordered_map
e tale alle versioni successive dello standard C ++.
map
è generalmente un btree equilibrato era dovuto all'uso operator<()
come mezzo per determinare la posizione.
map
è implementato da balanced binary search tree
(di solito a rb_tree
), poiché tutti i membri in balanced binary search tree
sono ordinati così è map;
hash_map
è implementato da hashtable
. Poiché tutti i membri in hashtable
non sono ordinati, i membri in hash_map(unordered_map)
non vengono ordinati.
hash_map
non è una libreria standard c ++, ma ora è rinominata unordered_map
(puoi pensare che sia stata rinominata) e diventa libreria standard c ++ poiché c ++ 11 vedi questa domanda Differenza tra hash_map e unordered_map? per maggiori dettagli.
Di seguito fornirò alcune interfacce principali dal codice sorgente su come è implementata la mappa a due tipi.
Il codice seguente è solo per mostrare che, map è solo un wrapper di una balanced binary search tree
, quasi tutta la sua funzione è solo invocare la balanced binary search tree
funzione.
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
è implementato dalla hashtable
cui struttura è un po 'come questa:
Nel codice seguente, darò la parte principale di hashtable
, e poi darà 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);
};
Come map's
solo il membro è rb_tree
, l' hash_map's
unico membro è hashtable
. È il codice principale come di seguito:
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);
};
};
L'immagine sotto mostra quando una hash_map ha 53 bucket e inserisce alcuni valori, la sua struttura interna.
L'immagine sotto mostra alcune differenze tra map e hash_map (unordered_map), l'immagine proviene da Come scegliere tra map e unordered_map? :
Non so cosa dia, ma hash_map impiega più di 20 secondi per clear () 150K chiavi intere senza segno e valori float. Sto solo correndo e leggendo il codice di qualcun altro.
Ecco come include hash_map.
#include "StdAfx.h"
#include <hash_map>
Ho letto questo qui https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap
dicendo che clear () è l'ordine di O (N). Questo per me è molto strano, ma è così.