Quand dois-je utiliser une Liste vs une LinkedList
Quand est-il préférable d'utiliser un Liste vs un LinkedList?
- Java q, ne devrait pas être très différent.
- Veuillez envisager de modifier la accepté de répondre. La version actuelle est inexacte et extrêmement trompeur.
- Veuillez envisager de modifier la accepté de répondre. La version actuelle est inexacte et extrêmement trompeur.
Vous devez vous connecter pour publier un commentaire.
Modifier
Réponse originale à cette question...
J'ai trouvé des résultats intéressants:
Liste chaînée (3,9 secondes)
Liste (2.4 secondes)
Même si vous avez seulement accès à des données, essentiellement, il est beaucoup plus lent!! Je dis ne jamais utiliser une linkedList.
Voici une autre comparaison effectuer un grand nombre de plaquettes (nous comptons sur l'insertion d'un élément au milieu de la liste)
Liste chaînée (51 secondes)
Liste (7.26 secondes)
Liste, après avoir tenu compte de l'emplacement où insérer (.04 secondes)
De sorte que si vous prévoyez sur l'insertion de plusieurs articles et vous aussi quelque part que la mention de l'endroit où vous prévoyez d'insérer l'élément, puis utiliser une liste chaînée. Juste parce que vous devez insérer un grand nombre d'éléments, qu'il ne veut pas en faire plus vite, car la recherche de l'emplacement où vous souhaitez insérer, il faut du temps.
list.AddLast(a);
dans les deux dernières LinkedList exemples? - Je le faire une fois avant la boucle, comme aveclist.AddLast(new Temp(1,1,1,1));
dans l'avant-dernier LinkedList, mais il semble (à moi) comme vous ajoutez deux fois autant de Temp objets dans les boucles elles-mêmes. (Et quand je double-vérifier moi-même avec une application de test, bien sûr, deux fois plus nombreux dans la LinkedList.)I say never use a linkedList.
est boiteuse, car votre post plus tard révèle. Vous pourriez voulez le modifier. 2) Quels sont vous un moment? L'instanciation, plus, et l'énumération complètement en une seule étape? Surtout, l'instanciation et l'énumération ne sont pas ce que ppl sont inquiets, ceux-ci sont un pas de temps. Plus précisément calendrier les inserts et les ajouts donnerait une meilleure idée. 3) le Plus important, vous êtes en train d'ajouter plus que nécessaire pour une linkedlist. C'est une mauvaise comparaison. Des écarts de fausse idée de linkedlist.Dans la plupart des cas,
List<T>
est plus utile.LinkedList<T>
aura moins de coût lors de l'ajout/suppression d'éléments dans le milieu de la liste, alors que lesList<T>
ne peut à moindre coût ajouter/supprimer à la fin de la liste.LinkedList<T>
est qu'il est plus efficace si vous accédez à des données séquentielles (soit en avant ou en arrière) à accès aléatoire est relativement cher, car il faut marcher sur la chaîne à chaque fois (donc pourquoi il n'a pas un indexeur). Toutefois, en raison duList<T>
est essentiellement juste un tableau (avec un wrapper) à accès aléatoire est très bien.List<T>
offre un grand nombre de méthodes de soutien -Find
,ToArray
, etc; cependant, ils sont également disponibles pourLinkedList<T>
avec .NET 3.5/C# 3.0 via des méthodes d'extension - si c'est un facteur moins important.List<T>
etT[]
échoue trop chunky (sur une dalle),LinkedList<T>
gémiront d'être trop précis (la dalle par élément).Array
réussit à l'allocation, il sera entièrement séquentielle; l'attribution faite dansResize
estnew T[newSize]
. tableau.cs.List
en interne unArray
, donc en est de même pour elle.LinkedList
n'est pas ce que vous voulez quand vous avez un grand nombre d'éléments: il alloue unLinkedListNode
par élément. ChaqueLinkedListNode
est d'une attribution distincte: il n'est pas unArray
de quoi que ce soit. Pas de continuité. Un beaucoup de mémoire utilisée pour les boutons précédent/suivant les indicateurs. googlec# LinkedList source code
.La pensée d'une liste, comme une liste peut être un peu trompeuse. C'est plus comme une chaîne. En fait, dans .NET,
LinkedList<T>
ne prend même pas la mettre en œuvreIList<T>
. Il n'y a pas de véritable concept de l'index dans une liste liée, même si cela peut paraître, il est. Certainement pas les méthodes de la classe accepter index.Listes liées peuvent être individuellement liée, ou doublement chaînée. Cela signifie que chaque élément de la chaîne a un lien seulement à la prochaine (individuellement liée) ou à la fois à l'avant/à côté des éléments (doublement chaînée).
LinkedList<T>
est doublement chaînée.En interne,
List<T>
est soutenu par un tableau. Cela donne une très compact représentation en mémoire. À l'inverse,LinkedList<T>
implique la mémoire supplémentaire pour stocker les liens bidirectionnels entre les éléments successifs. Donc, l'empreinte mémoire d'unLinkedList<T>
sera généralement plus grande que pourList<T>
(avec la réserve queList<T>
peut avoir inutilisés interne des éléments d'un tableau afin d'améliorer les performances lors d'ajouter des opérations.)Ils ont différentes caractéristiques de performance trop:
Ajouter
LinkedList<T>.AddLast(item)
constante de tempsList<T>.Add(item)
amorti à temps constant, linéaire pire des casAjouter
LinkedList<T>.AddFirst(item)
constante de tempsList<T>.Insert(0, item)
temps linéaireD'Insertion
LinkedList<T>.AddBefore(node, item)
constante de tempsLinkedList<T>.AddAfter(node, item)
constante de tempsList<T>.Insert(index, item)
temps linéaireSuppression
LinkedList<T>.Remove(item)
temps linéaireLinkedList<T>.Remove(node)
constante de tempsList<T>.Remove(item)
temps linéaireList<T>.RemoveAt(index)
temps linéaireCompter
LinkedList<T>.Count
constante de tempsList<T>.Count
constante de tempsContient
LinkedList<T>.Contains(item)
temps linéaireList<T>.Contains(item)
temps linéaireClair
LinkedList<T>.Clear()
temps linéaireList<T>.Clear()
temps linéaireComme vous pouvez le voir, ils sont essentiellement équivalents. Dans la pratique, l'API de
LinkedList<T>
est de plus en plus lourde à utiliser, et les détails de ses besoins internes répandre dans votre code.Toutefois, si vous avez besoin de faire beaucoup d'insertions/retraits de l'intérieur d'une liste, il propose à temps constant.
List<T>
offre linéaire dans le temps, comme des éléments de la liste doivent être réorganisées après l'insertion/suppression.LinkedList<T>
n'ont pas de membre pour l'accès par index. Vous pouvez toujours le faire à l'aide d'un méthode d'extension basé sur laIEnumerable<T>
qui propose bien entendu de temps linéaire de l'accès.Clear
. Les deux sont des O(n). La charge de la mémoire pour LinkedList vaut la peine de noter. Déjà upvoted.Clear
. Le troisième paragraphe traite de l'utilisation de la mémoire. Souhaitez-vous ajouter?Clear
est linéaire dans le temps, pas de temps constant pour les deux méthodes. Il est documenté dans msdn.List
, et écrire un algorithme aussi simplement que vous le pouvez, sans préoccupation pour la performance. Une fois votre code fonctionne correctement dans tous les cas de test que vous pouvez penser, le temps que cela. Si assez vite, passer à une autre tâche.List
(si le sous-jacent tableau est encore assez grande) devrait être assez rapide. L'insertion au début est bien sûr quelque chose d'autre.Listes liées fournir très rapidement insertion ou la suppression d'un membre de la liste. Chaque membre dans une liste contient un pointeur vers le prochain membre de la liste de manière à insérer un membre à la position i:
L'inconvénient d'une liste liée, c'est que l'accès aléatoire n'est pas possible. L'accès à un membre exige parcourant la liste jusqu'à ce que le membre est reconnu.
LinkedList
aide seulement quand vous avez un référence à l'élément à insérer, avant ou après. si vous avez de recherche pour l'élément, alors le temps sera dominé par la recherche linéaire. Si chaque élément est associé à un clé unique, puis uneDictionary
cartographie clé de l'élément vous donnera l'élément en O(1) fois. (E. g. si chaque élément a uneint Id
, et vous êtes de passage autour de cesId
s plutôt que de passer autour de références à des éléments, vous aurez envie cetteDictionary
.)La différence entre la Liste et le LinkedList réside dans leur implémentation sous-jacente. La liste est basé sur les tableau de la collection (ArrayList). LinkedList est le nœud du pointeur de la collection en fonction de (LinkedListNode). Sur le niveau de l'API d'utilisation, tous les deux sont à peu près la même depuis deux mettre en œuvre même ensemble d'interfaces telles que ICollection, IEnumerable, etc.
La principale différence vient lorsque le rendement de la matière. Par exemple, si vous êtes à la mise en œuvre de la liste qui a de lourdes "INSÉRER" de l'opération, LinkedList surpasse la Liste. Depuis LinkedList pouvez le faire en O(1) fois, mais la Liste peut-être besoin d'élargir la taille des sous-jacents au tableau. Pour plus de renseignements/détails vous pouvez lire sur l'algorithmique différence entre LinkedList et structures de données de tableau. http://en.wikipedia.org/wiki/Linked_list et Tableau
Espérons que cette aide,
Add
est toujours à la fin du tableau existant.List
est "assez bon" à qui, même si pas d'O(1). Le grave problème se produit si vous avez besoin de nombreusesAdd
s qui sont pas à la fin. Marc est de souligner que la nécessité de déplacer données existantes tous fois que vous insérez (et pas seulement lors de la redimensionner si nécessaire) est un plus considérable des performances du coût deList
.Ma réponse précédente n'a pas été assez précis.
Que vraiment c'était horrible 😀
Mais maintenant je peux poster beaucoup plus utile et de bonne réponse.
J'ai fait quelques tests supplémentaires. Vous pouvez le trouver à la source par le lien suivant et de les enregistrer sur votre environnement par votre propre: https://github.com/ukushu/DataStructuresTestsAndOther.git
Courte résultats:
Tableau nécessité d'utiliser:
Liste d'utilisation:
LinkedList besoin d'utiliser:
Plus de détails:
Intéressant de savoir:
LinkedList<T>
en interne n'est pas une Liste dans .NET. Il est même à ne pas mettre en œuvreIList<T>
. Et c'est pourquoi il y a absence d'index et des méthodes liées à l'index.LinkedList<T>
est le nœud du pointeur de la collection. Dans .NET il est en doublement chaînée de mise en œuvre. Cela signifie que suivant/précédent éléments en lien à l'élément courant. Et les données sont fragmentées -- les différents objets de la liste peuvent être situés dans différents endroits de la RAM. Il y aura aussi plus de mémoire utilisé pourLinkedList<T>
que pourList<T>
ou d'un Tableau.List<T>
dans .Net est de Java alternative deArrayList<T>
. Cela signifie que ce est la matrice de wrapper. Il est donc alloué dans la mémoire comme un bloc contigu de données. Si les données allouées taille dépasse 85000 octets, il sera déplacé vers des Objets Volumineux. En fonction de la taille, cela peut conduire à la fragmentation du segment(une forme bénigne de la fuite de mémoire). Mais dans le même temps, si la taille de l' < 85000 octets -- très compact et rapide d'accès à la représentation dans la mémoire.Seul bloc contigu est préféré pour un accès aléatoire de la performance et de la consommation de mémoire, mais pour les collections qui ont besoin de changer de taille régulièrement une structure telle qu'un Tableau général doivent être copiés vers un nouvel emplacement, alors qu'une liste liée seulement besoin de gérer la mémoire pour le nouvellement insérés ou supprimés nœuds.
Le principal avantage de listes liées au fil des tableaux, les liens nous fournir la capacité de réorganiser les éléments de manière efficace.
Sedgewick, p. 91
Quand vous en avez besoin intégrée de l'accès indexé, le tri (et d'après ce binaire de recherche), et "ToArray()" la méthode, vous devez utiliser la Liste.
Une circonstance commune à utiliser LinkedList est comme ceci:
Supposons que vous souhaitez supprimer de nombreux de certaines chaînes de caractères à partir d'une liste de chaînes de caractères avec une grande taille, disons de 100 000. Les chaînes de caractères à supprimer peut être recherché dans HashSet dic, et la liste des chaînes est censé contenir entre 30 000 à 60 000 chaînes à supprimer.
Alors quel est le meilleur type de Liste pour le stockage de 100 000 Chaînes? La réponse est LinkedList. S'ils sont stockés dans une liste de tableaux, puis en itérant sur elle et la suppression de Chaînes mises en correspondance devait prendre place
pour des milliards d'opérations, alors qu'il faut juste autour de 100 000 opérations à l'aide d'un itérateur et la méthode remove ().
RemoveAll
pour supprimer les éléments d'uneList
sans déplacement d'un grand nombre d'articles autour de, ou de l'utilisationWhere
de LINQ pour créer une seconde liste. À l'aide d'unLinkedList
ici, cependant, finit par consommer de de façon spectaculaire plus de mémoire que d'autres types de collections et de la perte de mémoire d'une localité signifie qu'il sera beaucoup plus lent que l'itération, ce qui en fait assez un peu de pire qu'unList
.RemoveAll
équivalent en Java.RemoveAll
n'est pas disponible pourList
, vous pourriez faire un "compactage" de l'algorithme, ce qui pourrait ressembler à Tom boucle, mais avec deux indices et de la nécessité de déplacer des éléments à être conservés une à une vers le bas dans la liste du tableau interne. L'efficacité est O(n), le même que Tom algorithme deLinkedList
. Dans les deux versions, le temps de calculer le HashSet clé pour les chaînes qui le domine. Ce n'est pas un bon exemple de cas d'utilisationLinkedList
.C'est adapté de Tono Nam's accepté de répondre à corriger de petites erreurs de mesures en elle.
Le test:
Et le code:
Vous pouvez le voir, les résultats sont en conformité avec la performance théorique d'autres ont documenté ici. Tout à fait clair -
LinkedList<T>
gains gros temps dans le cas d'insertions. Je n'ai pas testé pour le retrait du milieu de la liste, mais le résultat devrait être le même. Bien sûrList<T>
a d'autres domaines où il effectue une façon mieux comme O(1) à accès aléatoire.Essentiellement, un
List<>
dans .NET est un wrapper sur un tableau. UnLinkedList<>
est une liste liée. Donc, la question revient à, quelle est la différence entre un tableau et une liste chaînée, et quand un tableau sera utilisé à la place d'une liste chaînée. Probablement les deux facteurs les plus importants dans votre décision d'utiliser allait descendre pour:Je suis d'accord avec la plupart de la remarque faite ci-dessus. Et je suis aussi d'accord que la Liste ressemble à un choix plus évident, dans la plupart des cas.
Mais, je veux juste ajouter qu'il y a de nombreux cas où LinkedList sont un bien meilleur choix que de Liste, pour une meilleure efficacité.
Espère que quelqu'un aurait trouver ces commentaires utiles.
Utilisation
LinkedList<>
quandToken Stream
.Pour tout le reste, il est préférable d'utiliser
List<>
.LinkedListNode<T>
objets dans votre code. Si vous pouvez faire cela, alors c'est beaucoup mieux que d'utiliserList<T>
, en particulier pour les très longues listes où les insertions/suppressions sont fréquentes.node.Value
chaque fois que vous le souhaitez à l'élément d'origine). Afin de vous réécrire l'algorithme de travailler avec des nœuds, pas les valeurs brutes.LinkedList
, où il pourrait être la beaucoup objets, et les objets sont de petite taille, est que chaque objet nécessite une allocation supplémentaire - leLinkedListNode
qui est créé lorsque vous l'Ajoutez à la LinkedList. Le envers est que vous n'avez pas à acquérir un seul espace contigu de mémoire, de manière à éviter un éventuel problème de fragmentation de la mémoire. (Je n'ai jamais trouvé le coût de performances deList
internes Redimensionner à être importante; son comment la mémoire est utilisée dans la pratique.)Donc beaucoup de la moyenne des réponses ici...
Certains sont liés liste des implémentations d'utiliser des blocs de pré alloué nœuds. Si ils ne font pas ce que la constante de temps /temps linéaire est moins pertinent que les performances de la mémoire seront pauvres et les performances du cache encore pire.
Utiliser les listes chaînées quand
1) Vous voulez la sécurité des threads. Vous pouvez construire mieux "thread-safe" algos. Verrouillage des coûts de dominer en même temps une liste de style.
2) Si vous avez une grande file d'attente comme des structures et souhaitez supprimer ou ajouter n'importe où, mais à la fin tout le temps . >100K listes existent mais ne sont pas courantes.
J'ai demandé à un même question liée à la performance de la LinkedList collection, et découvert Steven Cleary C# en œuvre de Deque était une solution. Contrairement à la File d'attente de la collection, Deque permet de déplacer les éléments sur/hors tension avant et à l'arrière. Il est similaire à la liste chaînée, mais avec l'amélioration des performances.
Deque
est "semblable à une liste chaînée, mais avec l'amélioration des performances". Merci de nuancer cette affirmation:Deque
est de meilleures performances queLinkedList
, pour votre code. En suivant votre lien, je ne vois que deux jours plus tard que vous avez appris de Ivan Stoev que ce n'était pas une inefficacité de la LinkedList, mais d'une inefficacité dans votre code. (Et même si elle avait été d'une inefficacité de la LinkedList, qui ne serait pas justifier un énoncé général qui Deque est plus efficace; dans certains cas seulement.)