web-dev-qa-db-fra.com

Performances relatives de std :: vector vs std :: list vs std :: slist?

Pour une simple liste chaînée dans laquelle l'accès aléatoire aux éléments de la liste n'est pas une exigence, y a-t-il des avantages significatifs (performances ou autres) à utiliser std::list Au lieu de std::vector? Si une traversée vers l'arrière est requise, serait-il plus efficace d'utiliser std::slist Et reverse() la liste avant d'itérer sur ses éléments?

49
An̲̳̳drew

Comme d'habitude, la meilleure réponse aux questions de performances est de profile les deux implémentations de votre cas d'utilisation et de voir laquelle est la plus rapide.

En général, si vous avez des insertions dans la structure de données (sauf à la fin), alors vector peut être plus lent, sinon dans la plupart des cas, vector devrait fonctionner mieux que list si seulement pour problèmes de localisation des données , cela signifie que si deux éléments adjacents dans le jeu de données sont adjacents en mémoire, l'élément suivant sera déjà dans le cache du processeur et n'aura pas à paginer faille la mémoire dans le cache.

Gardez également à l'esprit que la surcharge d'espace pour un vector est constante (3 pointeurs) tandis que la surcharge d'espace pour un list est payée pour chaque élément, cela réduit également le nombre d'éléments complets (données plus les frais généraux) qui peuvent résider dans le cache à tout moment.

58
Motti

Non, tout simplement. La liste présente des avantages par rapport à Vector, mais l'accès séquentiel n'en fait pas partie - si c'est tout ce que vous faites, alors un vecteur est meilleur.

Cependant .. un vecteur coûte plus cher pour ajouter des éléments supplémentaires qu'une liste, surtout si vous l'insérez au milieu.

Comprenez comment ces collections sont implémentées: un vecteur est un tableau séquentiel de données, une liste est un élément qui contient les données et des pointeurs vers les éléments suivants. Une fois que vous aurez compris cela, vous comprendrez pourquoi les listes sont bonnes pour les insertions et mauvaises pour l'accès aléatoire.

(ainsi, l'itération inverse d'un vecteur est exactement la même que pour l'itération directe - l'itérateur soustrait simplement la taille des éléments de données à chaque fois, la liste doit toujours passer à l'élément suivant via le pointeur)

12
gbjbaanb

Quelques repères rigoureux sur le sujet: http://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html

Comme cela a été noté par d'autres, le stockage en mémoire contigu signifie que std :: vector est meilleur pour la plupart des choses. Il n'y a pratiquement aucune bonne raison d'utiliser std :: list, sauf pour de petites quantités de données (où elles peuvent toutes tenir dans le cache) et/ou où l'effacement et la réinsertion sont fréquents. Les garanties de complexité ne sont pas liées aux performances réelles en raison de la différence entre les vitesses de cache et de mémoire principale (200x) et de la façon dont l'accès à la mémoire contigu affecte l'utilisation du cache. Voir Chandler Carruth (google) parler du problème ici: https://www.youtube.com/watch?v=fHNmRkzxHWs

Et la conception orientée données de Mike Acton parle ici: https://www.youtube.com/watch?v=rX0ItVEVjHc

4
metamorphosis

Si vous avez besoin d'une traversée vers l'arrière, il est peu probable qu'une slist soit la structure de données pour vous.

Une liste conventionnelle (doublement) liée vous donne un temps d'insertion et de suppression constant n'importe où dans la liste; un vecteur ne donne que l'insertion et la suppression à temps constant amorti à la fin de la liste. Pour un vecteur, le temps d'insertion et de suppression est linéaire partout ailleurs qu'à la fin. Ce n'est pas toute l'histoire; il existe également des facteurs constants. Un vecteur est une structure de données plus simple qui présente des avantages et des inconvénients selon le contexte.

La meilleure façon de comprendre cela est de comprendre comment ils sont mis en œuvre. Une liste chaînée a un pointeur suivant et un pointeur précédent pour chaque élément. Un vecteur a un tableau d'éléments adressés par index. De cela, vous pouvez voir que les deux peuvent effectuer une traversée efficace vers l'avant et vers l'arrière, tandis que seul un vecteur peut fournir un accès aléatoire efficace. Vous pouvez également voir que la surcharge de mémoire d'une liste chaînée est par élément tandis que pour le vecteur, elle est constante. Et vous pouvez également voir pourquoi le temps d'insertion est différent entre les deux structures.

4
janm

Voir cette question pour plus de détails sur les coûts:
Quelles sont les garanties de complexité des conteneurs standard

Si vous avez un slist et que vous souhaitez maintenant le parcourir dans l'ordre inverse, pourquoi ne pas changer le type de liste partout?

2
Martin York