web-dev-qa-db-fra.com

vecteur ou carte, lequel utiliser?

J'ai entendu beaucoup de gens dire que si le nombre d'éléments attendus dans le conteneur est relativement petit, il est préférable d'utiliser std::vector au lieu de std::map même si j'utilise le conteneur uniquement pour la recherche et non pour l'itération.

Quelle est la vraie raison derrière cela?

Évidemment, les performances de la carte sur la consultation ne peuvent pas être pires que celles du vecteur (bien que cela puisse être en nanosecondes/microsecondes), est-ce que cela a quelque chose à voir avec l'utilisation de la mémoire?

Le vecteur gagne-t-il mieux/pire que la carte dans la fragmentation de l'espace d'adressage virtuel?

J'utilise la bibliothèque STL fournie avec Visual Studio (implémentation de Microsoft) fait-elle une différence par rapport aux autres implémentations?

59
Naveen

Je suppose que vous comparez map<A, B> avec vector<pair<A, B> >.

Premièrement, trouver un élément dans un très petit vecteur peut facilement être plus rapide que la même chose dans une carte, car toute la mémoire dans un vecteur est toujours contiguë (et joue donc mieux avec les caches des ordinateurs, etc.), et le nombre des comparaisons nécessaires pour trouver quelque chose dans un vecteur pourrait être à peu près le même que pour une carte. La recherche d'un élément sur une carte nécessite moins d'opérations dans la limite des très grands conteneurs. 

Le point où les cartes deviennent plus rapides que les vecteurs dépend de la mise en œuvre, de votre processeur, des données contenues dans la carte et de choses subtiles telles que la mémoire présente dans le cache du processeur. Généralement, le point où la carte devient plus rapide serait d'environ 5 à 30 éléments.

Une alternative consiste à utiliser un conteneur de hachage. Ils sont souvent nommés hash_map ou unordered_map. Les classes nommées hash_map ne font pas partie de la norme officielle (et il en existe quelques variantes); std::tr1::unordered_map est. Une carte de hachage est souvent plus rapide qu'une carte normale pour les recherches, quel que soit le nombre d'éléments qu'elle contient. Toutefois, sa rapidité dépend de la nature de la clé, de son mode de hachage, des valeurs à traiter et de la manière dont elles sont traitées. la clé est comparée dans std :: map. Il ne garde pas les choses dans un ordre spécifique comme std :: map, mais vous avez dit que vous vous en ficheiez. Je recommanderais les cartes de hachage, en particulier si les clés sont des entiers ou des pointeurs, car ces hachages sont très rapides.

59
Doug

Les cartes sont généralement implémentées sous forme d'arbres de recherche binaires, et marcher dans un arbre binaire entraîne toujours un léger surcoût (comparaisons, liens de marche, etc.) Les vecteurs ne sont en principe que des tableaux. Pour de très petites quantités de données, peut-être 8 ou 12 éléments, il est parfois plus rapide de faire une recherche linéaire sur un tableau plutôt que de parcourir un arbre de recherche binaire. 

Vous pouvez exécuter vous-même des chronométrages pour voir où se situe le seuil de rentabilité - effectuez une recherche sur quatre éléments, puis sur huit, puis sur seize et ainsi de suite, afin de trouver le meilleur compromis pour votre mise en œuvre particulière du TSL.

Les cartes ont tendance à avoir un tas de petites allocations sur tout le tas, alors que les vecteurs sont contigus, le taux d'accès au cache des vecteurs peut parfois être un peu meilleur dans les cas où vous parcourez tous les éléments de l'avant à l'arrière. 

27
Crashworks

"Par défaut, utilisez vector lorsque vous avez besoin d'un conteneur" - Bjarne Stroustrup.

Sinon, je trouve ce petit organigramme très utile:

http://homepages.e3.net.nz/~djm/cppcontainers.html

22
Stefan Rådström

Si vous effectuez toutes vos insertions à la fois puis effectuez de nombreuses recherches, vous pouvez utiliser un vecteur et le trier lorsque vous avez terminé l'insertion; puis utilisez lower_bound pour effectuer une recherche rapide. Cela peut être plus rapide que d'utiliser une carte, même pour un grand nombre d'éléments.

4
Mark Ransom

Une autre façon de voir les choses est que s’il s’agit de petits conteneurs, aucun d’entre eux ne mettra beaucoup de temps à chercher. À moins que vous ne cherchiez dans ce conteneur sur une boucle très étroite, la différence de temps sera probablement négligeable. 

Dans ce cas, je chercherais quel conteneur correspond le mieux à ce que vous voulez faire. Si vous recherchez une valeur particulière, la méthode native find () de map sera beaucoup plus facile (et moins complexe à utiliser) que de créer une boucle for et de faire une itération sur un vecteur. 

Votre temps vaut probablement plus que quelques nanosecondes ici et là.

3
teeks99

Je pense que vous devriez avant tout utiliser le conteneur qui correspond aux données. std :: vector est utilisé dans les situations où vous utiliseriez un tableau en C ou C++ pré-STL: vous voulez un bloc de mémoire contigu pour stocker les valeurs avec une recherche rapide dans le temps constant. std :: map doit être utilisé pour mapper les clés sur des valeurs. Le chevauchement principal ici est un vecteur vs une carte avec un size_t comme clé. Dans ce cas, il y a deux préoccupations: les index sont-ils continus? Sinon, vous allez probablement perdre de la mémoire avec un vecteur. Deuxièmement, quel temps de recherche voulez-vous? Un vecteur a une recherche constante dans le temps, alors que std :: map est généralement implémenté sous la forme d'une arborescence RB, qui a un temps de recherche O (log n), et même une carte de hachage (telle que TR1 unordered_map) est généralement plus complexe parce que l'index (ou un hash de celui-ci) sera mappé à un compartiment pouvant contenir plusieurs valeurs.

Si visaient un vecteur avec des paires: vous pouvez utiliser les éléments du vecteur et utiliser find pour trouver des éléments. Mais ceci est une recherche binaire, et sera pratiquement aussi rapide qu’un std :: map.

Quoi qu'il en soit, essayez de modéliser les données de manière évidente. L'optimisation prématurée n'aide souvent pas beaucoup.

3
danieldk

Fondamentalement, les cartes sont utilisées pour la recherche. 

Mais parfois, std::vector peut être utilisé à la place de std::map même pour les recherches.

S'il y a très peu d'éléments dans vos paires clé-valeur, vous pouvez effectuer une recherche itérative à l'aide de la clé, même dans std::vector<std::pair<x,y>>.

Cela est dû au fait que le hachage prend du temps, en particulier pour le hachage des chaînes et pour d'autres opérations dans la carte, comme le stockage de données dans le tas.

Vous ne verriez une meilleure différence que dans std :: map si vous avez plus d'éléments dans lesquels vous devez rechercher et si vous souhaitez effectuer des recherches fréquentes dans la liste des éléments que vous avez.

0
fury.slay