web-dev-qa-db-fra.com

map vs. hash_map en C ++

J'ai une question avec hash_map et map en C++. Je comprends que map est en STL, mais hash_map n'est pas une norme. Quelle est la différence entre les deux?

110
skydoor

Ils sont mis en œuvre de manières très différentes.

hash_map (unordered_map dans TR1 et Boost; utilisez plutôt ceux-ci) utilisez une table de hachage où la clé est hachée dans un emplacement de la table et la valeur est stockée dans une liste liée à cette clé.

map est implémenté comme un arbre de recherche binaire équilibré (généralement un arbre rouge/noir).

Un unordered_map devrait donner des performances légèrement meilleures pour accéder aux éléments connus de la collection, mais un map aura des caractéristiques supplémentaires utiles (par exemple, il est stocké dans un ordre trié, ce qui permet un parcours complet du début à la fin). unordered_map sera plus rapide lors de l'insertion et de la suppression qu'un map.

129
Joe

hash_map était une extension courante fournie par de nombreuses implémentations de bibliothèques. C’est exactement pourquoi il a été renommé unordered_map quand il a été ajouté à la norme C++ dans le cadre de TR1. La carte est généralement implémentée avec un arbre binaire équilibré comme un arbre rouge-noir (les implémentations varient bien sûr). hash_map et unordered_map sont généralement implémentés avec des tables de hachage. Ainsi, la commande n'est pas maintenue. unordered_map insertion/suppression/requête sera O(1) (temps constant) où mappe sera O (log n) où n est le nombre d’éléments dans la structure de données. Donc unordered_map est plus rapide et si vous ne vous souciez pas de l'ordre des éléments, préférez-le à map. Parfois, vous voulez maintenir l'ordre (ordonné par la clé) et pour cela map serait le choix.

34
janglin

Certaines des principales différences concernent les exigences de complexité.

  • Un map nécessite O(log(N)) heure pour les opérations d'insertion et de recherche, car il est implémenté sous la forme d'une structure de données arbre rouge-noir.

  • Un unordered_map Nécessite un temps 'moyen' de O(1) pour les insertions et les recherches, mais est autorisé à avoir un temps pire de O(N). En effet, il est implémenté à l'aide de la structure de données Hash Table.

Donc, généralement, unordered_map Sera plus rapide, mais en fonction des touches et de la fonction de hachage que vous stockez, cela peut devenir bien pire.

14
R Samuel Klatchko

La spécification C++ ne dit pas exactement quel algorithme vous devez utiliser pour les conteneurs STL. Cependant, il impose certaines contraintes sur leurs performances, ce qui exclut l'utilisation de tables de hachage pour map et d'autres conteneurs associatifs. (Elles sont le plus souvent implémentées avec des arbres rouges/noirs.) Ces contraintes exigent de meilleures performances dans le pire des cas pour ces conteneurs que les tables de hachage ne peuvent fournir.

Beaucoup de gens veulent vraiment des tables de hachage, cependant, les conteneurs associatifs STL à base de hachage sont une extension courante depuis des années. Par conséquent, ils ont ajouté unordered_map et autres versions ultérieures du standard C++.

4
Warren Young

map est implémenté à partir de balanced binary search tree (généralement un rb_tree), étant donné que tous les membres de balanced binary search tree sont triés, ainsi que map;

hash_map Est implémenté à partir de hashtable. Comme tous les membres de hashtable ne sont pas triés, les membres de hash_map(unordered_map) ne sont pas triés.

hash_map N'est pas une bibliothèque standard c ++, mais maintenant renommé en unordered_map (Vous pouvez le penser renommé) et devient la bibliothèque standard c ++ puisque c ++ 11 voit cette question Différence entre hash_map et unordered_map? pour plus de détails.

Ci-dessous, je donnerai une interface principale à partir du code source de la manière dont la carte de type deux est mise en œuvre.

carte:

Le code ci-dessous est juste pour montrer que, map est juste une enveloppe d'un balanced binary search tree, Presque toute sa fonction est juste d'appeler la fonction balanced binary search tree.

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 Est implémenté à partir de hashtable dont la structure ressemble à ceci:

enter image description here

Dans le code ci-dessous, je donnerai la partie principale de hashtable, puis 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);

};

Comme pour map's, Seul le membre est rb_tree, Le membre hash_map's Uniquement est hashtable. C'est le code principal ci-dessous:

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'image ci-dessous montre quand un hash_map a 53 compartiments et insère quelques valeurs, c'est sa structure interne.

enter image description here

L'image ci-dessous montre une différence entre map et hash_map (unordered_map), l'image provient de Comment choisir entre map et unordered_map? :

enter image description here

2
Jayhello

Je ne sais pas ce que cela donne, mais hash_map met plus de 20 secondes pour effacer () 150K de clés entières non signées et de valeurs flottantes. Je ne fais que courir et lire le code de quelqu'un d'autre.

Voici comment cela inclut hash_map.

#include "StdAfx.h"
#include <hash_map>

Je lis ceci ici https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap

dire que clear () est ordre de O (N). Pour moi, c'est très étrange, mais c'est comme ça.

0
BoBoDev