Résumé ArrayList
con ArrayDeque
sont préférables dans beaucoup de plus de cas d'utilisation que LinkedList
. Si vous n'êtes pas sûr - commencez simplement par ArrayList
.
TLDR, dans ArrayList l'accès à un élément prend un temps constant [O(1)] et l'ajout d'un élément prend un temps O(n) [pire cas]. Dans LinkedList, l'ajout d'un élément prend un temps O(n) et l'accès prend également un temps O(n) mais LinkedList utilise plus de mémoire que ArrayList.
LinkedList
y ArrayList
sont deux implémentations différentes de l'interface List. LinkedList
l'implémente avec une liste doublement liée. ArrayList
l'implémente avec un tableau qui se redimensionne dynamiquement.
Comme pour les opérations standard sur les listes et tableaux liés, les diverses méthodes auront des temps d'exécution algorithmiques différents.
Pour LinkedList<E>
-
get(int index)
es O(n) (avec n/4 pas en moyenne), mais O(1) quand index = 0
ou index = list.size() - 1
(dans ce cas, vous pouvez également utiliser getFirst()
y getLast()
). L'un des principaux avantages de LinkedList<E>
-
add(int index, E element)
es O(n) (avec n/4 pas en moyenne), mais O(1) quand index = 0
ou index = list.size() - 1
(dans ce cas, vous pouvez également utiliser addFirst()
y addLast()
/ add()
). L'un des principaux avantages de LinkedList<E>
-
remove(int index)
es O(n) (avec n/4 pas en moyenne), mais O(1) quand index = 0
ou index = list.size() - 1
(dans ce cas, vous pouvez également utiliser removeFirst()
y removeLast()
). L'un des principaux avantages de LinkedList<E>
-
Iterator.remove()
es O(1) . L'un des principaux avantages de LinkedList<E>
-
ListIterator.add(E element)
es O(1) . L'un des principaux avantages de LinkedList<E>
Remarque : de nombreuses opérations nécessitent n/4 pas en moyenne, constant nombre d'étapes dans le meilleur des cas (par exemple, indice = 0), et n/2 étapes dans le pire des cas (milieu de la liste)
Pour ArrayList<E>
-
get(int index)
es O(1) . Principal avantage de ArrayList<E>
-
add(E element)
es O(1) amortis, mais O(n) le pire cas puisque le tableau doit être redimensionné et copié
-
add(int index, E element)
es O(n) (avec n/2 pas en moyenne)
-
remove(int index)
es O(n) (avec n/2 pas en moyenne)
-
Iterator.remove()
es O(n) (avec n/2 pas en moyenne)
-
ListIterator.add(E element)
es O(n) (avec n/2 pas en moyenne)
Remarque : de nombreuses opérations nécessitent n/2 pas en moyenne, constant nombre d'étapes dans le meilleur des cas (fin de la liste), n étapes dans le pire des cas (début de la liste)
LinkedList<E>
permet des insertions ou des retraits en temps constant utiliser des itérateurs mais seulement l'accès séquentiel des éléments. En d'autres termes, vous pouvez parcourir la liste en avant ou en arrière, mais trouver une position dans la liste prend un temps proportionnel à la taille de la liste. La Javadoc dit "les opérations qui indexent la liste parcourront la liste depuis le début ou la fin, selon ce qui est le plus proche". Ces méthodes sont donc O(n) ( n/4 pas) en moyenne, bien que O(1) para index = 0
.
ArrayList<E>
D'autre part, ils permettent un accès rapide à la lecture aléatoire, de sorte que vous pouvez saisir n'importe quel élément en temps constant. Mais l'ajout ou la suppression d'un élément à partir de n'importe quel endroit sauf l'extrémité nécessite de déplacer tous les derniers éléments, soit pour créer une ouverture, soit pour combler le vide. De plus, si vous ajoutez plus d'éléments que la capacité du tableau sous-jacent, un nouveau tableau (1,5 fois la taille) est alloué, et l'ancien tableau est copié dans le nouveau. ArrayList
es O(n) dans le pire des cas mais constante en moyenne.
Ainsi, selon les opérations que vous avez l'intention d'effectuer, vous devez choisir les implémentations en conséquence. L'itération sur l'un ou l'autre type de liste est pratiquement aussi bon marché. (L'itération sur une ArrayList
est techniquement plus rapide, mais à moins que vous ne fassiez quelque chose de vraiment sensible aux performances, vous ne devriez pas vous soucier de cela -- ce sont toutes deux des constantes).
Les principaux avantages de l'utilisation d'un LinkedList
surviennent lorsque vous réutilisez des itérateurs existants pour insérer et supprimer des éléments. Ces opérations peuvent alors être effectuées dans O(1) en modifiant la liste localement seulement. Dans une liste de type tableau, le reste du tableau doit être déplacé (c'est-à-dire copié). D'un autre côté, la recherche dans un LinkedList
signifie suivre les liens dans O(n) ( n/2 étapes) dans le pire des cas, alors que dans un ArrayList
la position souhaitée peut être calculée mathématiquement et accessible en O(1) .
Un autre avantage de l'utilisation d'un LinkedList
se produit lorsque vous ajoutez ou retirez de la tête de la liste, car ces opérations sont O(1) alors qu'ils sont O(n) para ArrayList
. Notez que ArrayDeque
peut être une bonne alternative à LinkedList
pour ajouter et enlever de la tête, mais ce n'est pas une List
.
En outre, si vous avez de grandes listes, n'oubliez pas que l'utilisation de la mémoire est également différente. Chaque élément d'une LinkedList
est plus coûteux car les pointeurs vers les éléments suivants et précédents sont également stockés. ArrayLists
n'ont pas ces frais généraux. Cependant, ArrayLists
occupent autant de mémoire que celle qui est allouée à la capacité, que des éléments aient été effectivement ajoutés ou non.
La capacité initiale par défaut d'un ArrayList
est assez faible (10 de Java 1.4 à 1.8). Mais comme l'implémentation sous-jacente est un tableau, ce dernier doit être redimensionné si vous ajoutez beaucoup d'éléments. Pour éviter le coût élevé du redimensionnement lorsque vous savez que vous allez ajouter beaucoup d'éléments, construisez la balise ArrayList
avec une capacité initiale plus élevée.
Si l'on utilise la perspective des structures de données pour comprendre les deux structures, une LinkedList est fondamentalement une structure de données séquentielle qui contient un nœud de tête. Le Node est une enveloppe pour deux composants : une valeur de type T [acceptée par les génériques] et une autre référence au Node qui lui est lié. Ainsi, nous pouvons affirmer qu'il s'agit d'une structure de données récursive (un Node contient un autre Node qui a un autre Node et ainsi de suite...). L'ajout d'éléments prend un temps linéaire dans LinkedList comme indiqué ci-dessus.
Une ArrayList est un tableau évolutif. C'est exactement comme un tableau ordinaire. Lorsqu'un élément est ajouté et que la liste de tableaux est déjà pleine, elle crée un autre tableau dont la taille est supérieure à la taille précédente. Les éléments sont alors copiés du tableau précédent vers le nouveau et les éléments qui doivent être ajoutés sont également placés aux indices spécifiés.
7 votes
Voir aussi : Tableau et liste liée
9 votes
Il suffit de voir la citation de l'auteur de LinkedList stackoverflow.com/a/42529652/2032701 et vous aurez une idée concrète de la question.