2010-10-10 29 views
112

Maintenant que std a une vraie carte de hachage dans unordered_map, pourquoi (ou quand) que vous voudriez toujours utiliser le bon vieux map sur unordered_map sur les systèmes où il existe réellement? Y a-t-il des situations évidentes que je ne peux pas voir immédiatement?Le choix entre std :: carte et std :: unordered_map

+0

Copie possible de [Y a-t-il un avantage à utiliser la carte sur \ _map non ordonné en cas de clés triviales?] (Http://stackoverflow.com/questions/2196995/is-there-any-advantage-of-using- map-over-unordered-map-in-case-of-trivial-keys) –

Répondre

92

En tant que already mentioned, map permet d'itérer sur les éléments de manière triée, mais pas unordered_map. Ceci est très important dans de nombreuses situations, par exemple l'affichage d'une collection (par exemple un carnet d'adresses). Cela se manifeste également d'autres façons indirectes comme: (1) Démarrer l'itération de l'itérateur retourné par find(), ou (2) l'existence de fonctions membres comme lower_bound().

Aussi, je pense qu'il ya une certaine différence dans le pire des cas recherche complexité.

  • Pour map, il est O (logn)

  • Pour unordered_map, il est O (N) [Cette peut se produire lorsque la fonction de hachage n'est pas bon conduit à trop de collisions de hachage .]

La même chose est valable pour pire des cassuppression complexité.

+40

vous avez raison sur le pire des cas, mais ce post est en quelque sorte trompeur - comme en moyenne std :: unordered_map est O (1) pour la complexité de recherche qui est beaucoup mieux que std :: map –

+3

Il est très important de comprendre que pour certaines applications, la pire des performances est essentielle à connaître et est le facteur décisif. Pour certains systèmes durs en temps réel, il n'est pas acceptable d'avoir un pire cas linéaire comme la hashtable. std :: map est toujours O (lg N), ce qui est une très belle propriété à avoir. –

21

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

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 intuitive).

80

En plus des réponses ci-dessus, vous devriez également noter que juste parce que unordered_map est une vitesse constante (O(1)) ne veut pas dire qu'il est plus rapide que map (de l'ordre log(N)). La constante peut être plus grande que log(N), d'autant plus que N est limitée par 2 (ou 2).

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

Par exemple, dans un programme que je courais un blog post j'ai vu 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

note 3 au 5 barres.

+0

quelle est la valeur de N dans ce graphique? – paulm

+0

@paulm, comme je l'ai déclaré dans le [blog] (http://lanzkron.wordpress.com/2010/06/02/optimizing-collatz-for-klutzes/) 'N = 10.000.000'. – Motti

+0

Le lien de blog est allé le chemin du dodo, et les résultats présentés ici sont de peu de valeur sans ce contexte, comme le temps nécessaire pour hachage vs comparer varie énormément avec la fonction de hachage exact, le type de données, la longueur et les valeurs . Cela est particulièrement important avec la VC++ Standard Library, car les fonctions de hachage sont rapides mais sujettes aux collisions: les nombres traversés inaltérés, seuls 10 caractères espacés le long d'une chaîne de longueur quelconque sont combinés dans la valeur de hachage, les comptes de baquets ne sont pas premiers. (GNU est à l'extrémité opposée du spectre). –

19

Cela est dû à Chandler Carruth de Google dans son CppCon 2014 lecture

std::map est (considéré par beaucoup comme) pas utile pour le travail axé sur la performance: Si vous voulez O (1) -amortized accès, utilisez un tableau associatif approprié (ou par défaut d'un, 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 traverser, ou le rééquilibrer, incroyablement souvent. Ce sont respectivement les opérations cache-killer et cache-apocalypse ... alors dites NON à std::map.

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

(PS -. std::unordered_map est cache-hostile, car il utilise des listes chaînées comme des seaux)

6

Supposons que vous avez des clés très grandes, peut-être de grandes chaînes. Pour créer une valeur de hachage pour une grande chaîne, vous devez parcourir toute la chaîne du début à la fin. Il faudra au moins un temps linéaire à la longueur de la clé. Toutefois, lorsque vous recherchez uniquement un arbre binaire à l'aide de l'opérateur > de la clé, chaque comparaison de chaîne peut renvoyer lorsque la première disparité 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 en utilisant la recherche binaire (dans le cas de std::map), la recherche devrait être plus rapide une clé dans le std::map. Il est assez facile de penser à des scénarios où ce serait le cas, mais ils seraient assez rares dans la pratique, je crois.