web-dev-qa-db-fra.com

Choisir entre std :: map et std :: unordered_map

Maintenant que std a une vraie carte de hachage dans unordered_map, pourquoi (ou quand) voudrais-je quand même utiliser le bon vieux map sur unordered_map sur des systèmes où il existe réellement? Existe-t-il des situations évidentes que je ne peux pas voir immédiatement?

129
Johann Gerell

Comme déjà mentionné , map permet de parcourir les éléments de manière triée, mais pas unordered_map. Ceci est très important dans de nombreuses situations, par exemple pour afficher une collection (par exemple, un carnet d'adresses). Cela se manifeste également de manière indirecte, par exemple: (1) Commencez par itérer à partir de l'itérateur renvoyé par find(), ou (2) par l'existence de fonctions membres telles que lower_bound().

De plus, je pense qu’il ya une différence dans le pire recherche complexité.

  • Pour map, c’est O (lg N)

  • Pour unordered_map, Il s'agit de O (N) [Ceci peut se produire lorsque la fonction de hachage n'est pas bonne, ce qui entraîne un trop grand nombre de collisions de hachage.]

La même chose s'applique pour le pire des cas suppression complexité.

108
Arun

En plus des réponses ci-dessus, vous devez également noter que le fait que unordered_map Soit à vitesse constante (O(1)) ne signifie pas que c'est plus rapide que map (d'ordre log(N)). La constante peut être plus grande que log(N) d'autant plus que N est limité à 232 (ou 264).

Donc, en plus des autres réponses (map maintient les commandes et les fonctions de hachage peuvent être difficiles), il se peut que map soit plus performant.

Par exemple, dans un programme que j'ai exécuté pendant billet de blog , j'ai constaté que pour VS10 std::unordered_map Était plus lent que std::map (Bien que boost::unordered_map Était plus rapide que les deux ).

Performance Graph

Notez les barres 3 à 5.

85
Motti

Cela est dû à Chandler Carruth de Google dans son conférence CppCon 2014

std::map Est (considéré par beaucoup comme étant) inutile pour les travaux orientés sur les performances: si vous voulez un accès amorti par O (1), utilisez un tableau associatif approprié (ou à défaut, std::unorderded_map); si vous voulez un accès séquentiel trié, utilisez quelque chose basé sur un vecteur.

En outre, std::map Est un arbre équilibré. et vous devez le parcourir, ou le rééquilibrer, incroyablement souvent. Ce sont des opérations de cache-killer et de cache-apocalypse, respectivement ... alors dites simplement NON à std::map.

Vous pourriez être intéressé par this SO question ) sur les implémentations efficaces de la carte de hachage.

(PS - std::unordered_map N'approuve pas le cache, car il utilise des listes chaînées comme compartiments.)

25
einpoklum

Je pense qu'il est évident que vous utiliseriez le std::map vous devez parcourir les éléments de la carte en ordre trié.

Vous pouvez également l'utiliser lorsque vous préférez écrire un opérateur de comparaison (qui est intuitif) au lieu d'une fonction de hachage (qui est généralement très peu intuitif).

21
Ken Bloom

Supposons que vous ayez de très grandes clés, peut-être de grandes chaînes. Pour créer une valeur de hachage pour une chaîne de grande taille, vous devez parcourir l'intégralité de la chaîne du début à la fin. Cela prendra au moins un temps linéaire à la longueur de la clé. Cependant, lorsque vous recherchez uniquement une arborescence binaire à l'aide de la commande > opérateur de la clé que chaque comparaison de chaîne peut renvoyer lorsque la première incompatibilité est trouvée. C'est généralement très tôt pour les grandes chaînes.

Ce raisonnement peut être appliqué à la fonction find de std::unordered_map et std::map. Si la nature de la clé est telle qu'il faut plus de temps pour produire un hachage (dans le cas de std::unordered_map) que pour trouver l'emplacement d'un élément à l'aide d'une recherche binaire (dans le cas de std::map), il devrait être plus rapide de rechercher une clé dans le std::map. Il est assez facile de penser à des scénarios dans lesquels ce serait le cas, mais ils seraient assez rares dans la pratique, je crois.

9
Martin G