Quand utiliser LinkedList over ArrayList en Java?
j'ai toujours été du genre à utiliser simplement:
List<String> names = new ArrayList<>();
j'utilise l'interface comme nom de type pour portabilité , de sorte que lorsque je pose des questions comme celles-ci, je peux retravailler mon code.
"quand utiliser LinkedList
plutôt que ArrayList
et vice-versa?
30 réponses
Résumé ArrayList
avec ArrayDeque
est préférable à beaucoup plus de cas d'utilisation de LinkedList
. Si vous n'êtes pas sûr, commencez par ArrayList
.
LinkedList
et ArrayList
sont deux implémentations différentes de L'interface de liste. LinkedList
l'implémente avec une liste doublement liée. ArrayList
l'implémente avec un tableau de re-dimensionnement dynamique.
comme pour les opérations de liste et de tableau liées standard, les différentes méthodes auront des durées d'exécution algorithmiques différentes.
pour LinkedList<E>
-
get(int index)
est O(n) (avec les n/4 les étapes de la moyenne) -
add(E element)
is O(1) -
add(int index, E element)
est O(n) (avec n/4 pas en moyenne), mais O (1) quandindex = 0
< - - - principal avantage deLinkedList<E>
-
remove(int index)
est O(n) (avec les n/4 les étapes de la moyenne) -
Iterator.remove()
est O(1) . < - - - principal avantage deLinkedList<E>
-
ListIterator.add(E element)
est O(1) C'est l'un des principaux avantages deLinkedList<E>
Remarque: la plupart des opérations de besoin n/4 les étapes de la moyenne", constante nombre d'étapes dans le meilleur des cas (p. ex., indice = 0), et n/2 étapes dans le pire des cas (milieu de la liste)
pour ArrayList<E>
-
get(int index)
est O(1) <--- principal avantage de laArrayList<E>
-
add(E element)
est O(1) amorti, mais O(n) pire-cas depuis le tableau doit être redimensionnée et copié -
add(int index, E element)
est O(n) (avec les n/2 les étapes de la moyenne) -
remove(int index)
est O(n) (avec n/2 pas en moyenne) -
Iterator.remove()
est O(n) (avec les n/2 les étapes de la moyenne) -
ListIterator.add(E element)
est O(n) (avec les n/2 les étapes de la moyenne)
Note: de nombreuses opérations nécessitent n / 2 pas en moyenne, constante nombre d'étapes dans le meilleur des cas (fin de liste), n dans le pire des cas (début de la liste)
LinkedList<E>
permet des insertions ou des suppressions à temps constant en utilisant 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 de trouver une position dans la liste prend du temps proportionnel à la taille de la liste. Javadoc dit "les opérations qui indexent dans la liste traverseront la liste depuis le début ou la fin, celle qui est la plus proche" , donc ces méthodes sont O(n) ( n/4 steps) en moyenne, bien que o(1) pour index = 0
.
ArrayList<E>
, d'autre part, permettent un accès rapide au hasard de lecture, de sorte que vous pouvez saisir n'importe quel élément en temps constant. Mais l'ajout ou le retrait de n'importe où mais la fin nécessite déplacer tous ces derniers éléments, soit pour faire une ouverture, soit pour combler le vide. En outre, 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é sur le nouveau, donc l'ajout à un ArrayList
est O(n) dans le pire des cas mais constante en moyenne.
ainsi, selon les opérations que vous avez l'intention de faire, vous devez choisir les implémentations en conséquence. Itérer concernant soit le type de Liste est pratiquement aussi bon marché. (Itérer sur un ArrayList
est techniquement plus rapide, mais à moins que vous ne fassiez quelque chose de vraiment sensible aux performances, vous ne devriez pas vous en inquiéter -- ce sont deux constantes.)
les principaux avantages de l'utilisation d'un LinkedList
apparaissent 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 changeant la liste localement seulement. Dans un tableau list, le reste du tableau doit être déplacé (c'est-à-dire copié). De l'autre côté, chercher dans un LinkedList
signifie suivre les liens dans O(n) ( n/2 steps) pour le pire des cas, tandis que dans un ArrayList
la position désirée peut être calculée mathématiquement et accessible dans o(1) .
un autre avantage de l'utilisation d'un LinkedList
se produit lorsque vous ajoutez ou retirez de la chef de la liste, puisque ces opérations sont O(1) , alors qu'ils sont O(n) pour ArrayList
. Notez que ArrayDeque
peut être une bonne alternative à LinkedList
pour ajouter et enlever de la tête, mais ce n'est pas un List
.
Aussi, si vous avez de grandes listes, gardez à l'esprit que l'utilisation de la mémoire est également différente. Chaque élément d'un LinkedList
a plus de overhead puisque les pointeurs vers les éléments suivants et précédents sont également stockées. ArrayLists
Je n'ai pas ces frais généraux. Toutefois, ArrayLists
absorbe autant de mémoire que la capacité attribuée, que des éléments aient été ajoutés ou non.
la capacité initiale par défaut d'un ArrayList
est assez faible (10 de Java 1.4 - 1.8). Mais puisque l'implémentation sous-jacente est un tableau, le tableau doit être redimensionné si vous ajoutez beaucoup d'éléments. Pour éviter le coût élevé de redimensionnement lorsque vous savez que vous allez à ajouter beaucoup de elements, construire le ArrayList
avec une plus grande capacité initiale.
jusqu'à présent, personne ne semble avoir abordé l'empreinte mémoire de chacune de ces listes à part le consensus général qu'un LinkedList
est" beaucoup plus "qu'un ArrayList
donc j'ai fait quelques calculs pour montrer exactement combien les deux listes prennent pour n références nulles.
puisque les références sont 32 ou 64 bits (même si nul) sur leurs systèmes relatifs, j'ai inclus 4 ensembles de données pour 32 et 64 bits LinkedLists
et ArrayLists
.
Note: les tailles indiquées pour les lignes ArrayList
correspondent aux listes tronquées - en pratique, la capacité du backing-array dans un ArrayList
est généralement plus grande que son nombre actuel d'éléments.
Note 2: (merci BeeOnRope) comme CompressedOops est par défaut à partir de mid JDK6 et plus, les valeurs ci-dessous pour les machines 64 bits seront essentiellement correspondent à leurs homologues 32 bits, à moins bien sûr que vous éteignez spécifiquement.
le résultat montre clairement que LinkedList
est beaucoup plus que ArrayList
, surtout avec un nombre d'éléments très élevé. Si la mémoire est un facteur, évitez LinkedLists
.
les formules que j'ai utilisées suivent, faites-moi savoir si j'ai fait quelque chose de mal et je vais le corriger. "b" est 4 ou 8 pour les systèmes 32 ou 64 bits, et " n " est le nombre d'éléments. Notez que la raison pour les mods est que tous les objets en java prendront un multiple de 8 octets d'espace, qu'ils soient tous utilisés ou non.
ArrayList
:
ArrayList object header + size integer + modCount integer + array reference + (array oject header + b * n) + MOD(array oject, 8) + MOD(ArrayList object, 8) == 8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8) + MOD(8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8), 8)
LinkedList
:
LinkedList object header + size integer + modCount integer + reference to header + reference to footer + (node object overhead + reference to previous element + reference to next element + reference to element) * n) + MOD(node object, 8) * n + MOD(LinkedList object, 8) == 8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n + MOD(8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n, 8)
ArrayList
est ce que vous voulez. LinkedList
est presque toujours un bug (de performance).
pourquoi LinkedList
craint:
- il utilise beaucoup de petits objets de mémoire, et affecte donc la performance tout au long du processus.
- beaucoup de petits objets sont mauvais pour cache-locality.
- toute opération indexée nécessite une opération transversale, c'est-à-dire une performance O(n). Ce n'est pas évident dans la source code, conduisant à des algorithmes O(n) plus lent que si
ArrayList
a été utilisé. - obtenir une bonne performance est délicat.
- même si la performance du big-O est la même que celle du
ArrayList
, elle sera probablement beaucoup plus lente de toute façon. - il est troublant de voir
LinkedList
dans la source parce que c'est probablement le mauvais choix.
en tant que quelqu'un qui a fait l'ingénierie de performance opérationnelle à très grande échelle SOA web services depuis environ une décennie, je préférerais le comportement de LinkedList plutôt que ArrayList. Alors que le débit stable de LinkedList est pire et pourrait donc conduire à acheter plus de matériel -- le comportement de ArrayList sous pression pourrait conduire à des applications dans un cluster d'étendre leurs réseaux en quasi synchronicité et pour les grandes tailles de réseaux pourrait conduire à un manque de réactivité dans l'application et une panne, sous pression, ce qui est un comportement catastrophique.
de la même manière, vous pouvez obtenir un meilleur débit dans une application à partir du débit par défaut collecteur de déchets tenured, mais une fois que vous obtenez des applications java avec des tas de 10 Go, vous pouvez finir par verrouiller l'application pendant 25 secondes pendant un GCs complet qui provoque des arrêts de durée et des échecs dans les applications SOA et souffle vos SLAs si elle se produit trop souvent. Même si le collecteur CMS prend plus de ressources et n'atteint pas la même le débit, c'est un bien meilleur choix parce qu'il a une latence plus prévisible et plus petite.
ArrayList est seulement un meilleur choix pour la performance si tout ce que vous entendez par performance est le débit et vous pouvez ignorer la latence. D'après mon expérience à mon travail, je ne peux pas ignorer la pire des latences.
Algorithm ArrayList LinkedList
seek front O(1) O(1)
seek back O(1) O(1)
seek to index O(1) O(N)
insert at front O(N) O(1)
insert at back O(1) O(1)
insert after an item O(N) O(1)
ArrayLists sont bons pour l'écriture-une fois-lire-beaucoup ou appenders, mais mauvais à ajouter/enlever de l'avant ou au milieu.
Oui, je sais, c'est une question ancienne, mais je vais jeter dans mes deux cents:
LinkedList est presque toujours le mauvais choix, en terme de performance. Il existe des algorithmes très spécifiques pour lesquels une liste de liens est nécessaire, mais ceux-ci sont très, très rares et l'algorithme dépendra généralement spécifiquement de la capacité de LinkedList à insérer et supprimer des éléments au milieu de la liste relativement rapidement, une fois que vous y aurez navigué avec un ListIterator.
il existe un cas d'usage courant dans lequel LinkedList dépasse ArrayList: celui d'une file d'attente. Cependant, si votre objectif est la performance, au lieu de LinkedList, vous devriez également envisager d'utiliser un ArrayBlockingQueue (si vous pouvez déterminer une limite supérieure sur votre taille de file d'attente à l'avance, et pouvez vous permettre d'allouer toute la mémoire à l'avance), ou ce CircularArrayList implementation . (Oui, c'est de 2001, donc vous aurez besoin de le généraliser, mais je
c'est une question d'efficacité. LinkedList
est rapide pour ajouter et supprimer des éléments, mais lent pour accéder à un élément spécifique. ArrayList
est rapide pour accéder à un élément spécifique, mais peut être lente, à ajouter à chaque extrémité, et particulièrement lente à supprimer dans le milieu.
Array vs ArrayList vs LinkedList vs Vector va plus en profondeur, comme le fait Liste .
Correct ou Incorrect: veuillez exécuter le test localement et décider vous-même!
Edit / Remove est plus rapide dans LinkedList
que dans ArrayList
.
ArrayList
, soutenu par Array
, qui doit être le double de la taille, est pire dans l'application de grand volume.
ci-dessous est le résultat de l'essai unitaire pour chaque opération.Le Timing est donné en nanosecondes.
Operation ArrayList LinkedList
AddAll (Insert) 101,16719 2623,29291
Add (Insert-Sequentially) 152,46840 966,62216
Add (insert-randomly) 36527 29193
remove (Delete) 20,56,9095 20,45,4904
contains (Search) 186,15,704 189,64,981
voici le code:
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
public class ArrayListVsLinkedList {
private static final int MAX = 500000;
String[] strings = maxArray();
////////////// ADD ALL ////////////////////////////////////////
@Test
public void arrayListAddAll() {
Watch watch = new Watch();
List<String> stringList = Arrays.asList(strings);
List<String> arrayList = new ArrayList<String>(MAX);
watch.start();
arrayList.addAll(stringList);
watch.totalTime("Array List addAll() = ");//101,16719 Nanoseconds
}
@Test
public void linkedListAddAll() throws Exception {
Watch watch = new Watch();
List<String> stringList = Arrays.asList(strings);
watch.start();
List<String> linkedList = new LinkedList<String>();
linkedList.addAll(stringList);
watch.totalTime("Linked List addAll() = "); //2623,29291 Nanoseconds
}
//Note: ArrayList is 26 time faster here than LinkedList for addAll()
///////////////// INSERT /////////////////////////////////////////////
@Test
public void arrayListAdd() {
Watch watch = new Watch();
List<String> arrayList = new ArrayList<String>(MAX);
watch.start();
for (String string : strings)
arrayList.add(string);
watch.totalTime("Array List add() = ");//152,46840 Nanoseconds
}
@Test
public void linkedListAdd() {
Watch watch = new Watch();
List<String> linkedList = new LinkedList<String>();
watch.start();
for (String string : strings)
linkedList.add(string);
watch.totalTime("Linked List add() = "); //966,62216 Nanoseconds
}
//Note: ArrayList is 9 times faster than LinkedList for add sequentially
/////////////////// INSERT IN BETWEEN ///////////////////////////////////////
@Test
public void arrayListInsertOne() {
Watch watch = new Watch();
List<String> stringList = Arrays.asList(strings);
List<String> arrayList = new ArrayList<String>(MAX + MAX / 10);
arrayList.addAll(stringList);
String insertString0 = getString(true, MAX / 2 + 10);
String insertString1 = getString(true, MAX / 2 + 20);
String insertString2 = getString(true, MAX / 2 + 30);
String insertString3 = getString(true, MAX / 2 + 40);
watch.start();
arrayList.add(insertString0);
arrayList.add(insertString1);
arrayList.add(insertString2);
arrayList.add(insertString3);
watch.totalTime("Array List add() = ");//36527
}
@Test
public void linkedListInsertOne() {
Watch watch = new Watch();
List<String> stringList = Arrays.asList(strings);
List<String> linkedList = new LinkedList<String>();
linkedList.addAll(stringList);
String insertString0 = getString(true, MAX / 2 + 10);
String insertString1 = getString(true, MAX / 2 + 20);
String insertString2 = getString(true, MAX / 2 + 30);
String insertString3 = getString(true, MAX / 2 + 40);
watch.start();
linkedList.add(insertString0);
linkedList.add(insertString1);
linkedList.add(insertString2);
linkedList.add(insertString3);
watch.totalTime("Linked List add = ");//29193
}
//Note: LinkedList is 3000 nanosecond faster than ArrayList for insert randomly.
////////////////// DELETE //////////////////////////////////////////////////////
@Test
public void arrayListRemove() throws Exception {
Watch watch = new Watch();
List<String> stringList = Arrays.asList(strings);
List<String> arrayList = new ArrayList<String>(MAX);
arrayList.addAll(stringList);
String searchString0 = getString(true, MAX / 2 + 10);
String searchString1 = getString(true, MAX / 2 + 20);
watch.start();
arrayList.remove(searchString0);
arrayList.remove(searchString1);
watch.totalTime("Array List remove() = ");//20,56,9095 Nanoseconds
}
@Test
public void linkedListRemove() throws Exception {
Watch watch = new Watch();
List<String> linkedList = new LinkedList<String>();
linkedList.addAll(Arrays.asList(strings));
String searchString0 = getString(true, MAX / 2 + 10);
String searchString1 = getString(true, MAX / 2 + 20);
watch.start();
linkedList.remove(searchString0);
linkedList.remove(searchString1);
watch.totalTime("Linked List remove = ");//20,45,4904 Nanoseconds
}
//Note: LinkedList is 10 millisecond faster than ArrayList while removing item.
///////////////////// SEARCH ///////////////////////////////////////////
@Test
public void arrayListSearch() throws Exception {
Watch watch = new Watch();
List<String> stringList = Arrays.asList(strings);
List<String> arrayList = new ArrayList<String>(MAX);
arrayList.addAll(stringList);
String searchString0 = getString(true, MAX / 2 + 10);
String searchString1 = getString(true, MAX / 2 + 20);
watch.start();
arrayList.contains(searchString0);
arrayList.contains(searchString1);
watch.totalTime("Array List addAll() time = ");//186,15,704
}
@Test
public void linkedListSearch() throws Exception {
Watch watch = new Watch();
List<String> linkedList = new LinkedList<String>();
linkedList.addAll(Arrays.asList(strings));
String searchString0 = getString(true, MAX / 2 + 10);
String searchString1 = getString(true, MAX / 2 + 20);
watch.start();
linkedList.contains(searchString0);
linkedList.contains(searchString1);
watch.totalTime("Linked List addAll() time = ");//189,64,981
}
//Note: Linked List is 500 Milliseconds faster than ArrayList
class Watch {
private long startTime;
private long endTime;
public void start() {
startTime = System.nanoTime();
}
private void stop() {
endTime = System.nanoTime();
}
public void totalTime(String s) {
stop();
System.out.println(s + (endTime - startTime));
}
}
private String[] maxArray() {
String[] strings = new String[MAX];
Boolean result = Boolean.TRUE;
for (int i = 0; i < MAX; i++) {
strings[i] = getString(result, i);
result = !result;
}
return strings;
}
private String getString(Boolean result, int i) {
return String.valueOf(result) + i + String.valueOf(!result);
}
}
ArrayList
est essentiellement un tableau. LinkedList
est implémenté sous la forme d'une liste double liée.
le get
est assez clair. O (1) pour ArrayList
, parce que ArrayList
permettent un accès aléatoire en utilisant index. O (n) pour LinkedList
, parce qu'il a besoin de trouver l'index en premier. Note: il existe différentes versions de add
et remove
.
LinkedList
est plus rapide dans add et remove, mais plus lent dans get. En bref, LinkedList
devrait être préféré si:
- il n'y a pas grand nombre de l'accès aléatoire de l'élément
- il y a un grand nombre d'ajouter/supprimer des opérations
=== ArrayList = = =
- ajouter(E e)
- ajouter à la fin de ArrayList
- nécessite un coût de redimensionnement de la mémoire.
- O(n) sur les pires, O(1) amorti
- ajouter (index int, élément E))
- ajouter à une position d'index spécifique
- exiger le déplacement et la mémoire possible redimensionnement coût
- O (n)
- supprimer (index int)
- supprimer un élément spécifié
- nécessitent un déplacement et un possible redimensionnement de la mémoire coût
- O (n)
- supprimer (objet o)
- supprimer la première occurrence de l'élément spécifié de cette liste
- besoin de rechercher l'élément en premier, puis déplacement et de la mémoire possible redimensionnement coût
- O (n)
=== LinkedList = = =
-
ajouter(E)
- ajouter à la fin de la liste
- O (1)
-
add (int index, e element)
- insérer à la position spécifiée
- besoin de trouver la position en premier
- O (n)
- supprimer()
- supprimer le premier élément de la liste
- O (1)
- supprimer (index int)
- supprimer l'élément avec l'index spécifié
- besoin de trouver l'élément en premier
- O (n)
- supprimer (objet o)
- supprimer la première occurrence de l'élément spécifié
- besoin de trouver l'élément d'abord
- O (n)
Voici un schéma de programcreek.com ( add
et remove
sont du premier type, c'est à dire, ajouter un élément à la fin de la liste et supprimer l'élément à la position spécifiée dans la liste.):
ArrayList
est accessible au hasard, tandis que LinkedList
est vraiment bon marché pour étendre et supprimer des éléments. Pour la plupart des cas, ArrayList
est très bien.
sauf si vous avez créé de grandes listes et mesuré un goulot d'étranglement, vous n'aurez probablement jamais besoin de se soucier de la différence.
1) Recherche: ArrayList opération de recherche est assez rapide par rapport à la LinkedList opération de recherche. get(int index) in ArrayList donne la performance de O(1) alors que la performance LinkedList est O (n).
raison: ArrayList maintient un système basé sur l'index pour ses éléments car il utilise implicitement la structure de données de tableau ce qui le rend plus rapide pour la recherche d'un élément dans la liste. De l'autre côté, LinkedList implémente une liste doublement liée qui nécessite la traversée de tous les éléments pour la recherche d'un élément.
2) Deletion: LinkedList supprimer opération donne O(1) la performance tandis que ArrayList donne la performance variable: O(n) dans le pire des cas (tout en enlevant le premier élément) et O(1) dans le meilleur des cas (tout en enlevant le dernier élément).
Conclusion: la suppression de l'élément de la liste de liens est plus rapide que Liste de tableaux.
raison: chacun des éléments de LinkedList contient deux pointeurs (adresses), qui pointent vers les deux éléments voisins de la liste. Ainsi que l'enlèvement nécessite un changement dans la position du pointeur dans les deux nœuds voisins (éléments) du noeud qui va être supprimé. Alors que dans ArrayList tous les éléments doivent être décalés pour remplir l'espace créé par l'élément enlevé.
3) Insère La Performance: LinkedList ajouter une méthode donne O(1) les performances tout en ArrayList donne O(n) dans le pire des cas. La raison en est même comme il est expliqué pour les supprimer.
4) mémoire aérienne: ArrayList maintient des indices et des données d'élément tandis que LinkedList maintient des données d'élément et deux pointeurs pour les noeuds voisins donc la consommation de mémoire est élevée dans LinkedList comparativement.
Il y a quelques similitudes entre ces classes sont les suivantes:
les deux tableaux ArrayList et LinkedList sont des implémentations de L'interface List. Ils maintiennent tous les deux l'ordre d'insertion des éléments, ce qui signifie que tout en affichant les éléments ArrayList et LinkedList, le résultat serait d'avoir le même ordre dans lequel les éléments ont été insérés dans la liste. Ces deux classes ne sont pas synchronisées et peuvent être rendues explicitement synchronisées en utilisant Collections.synchronizedList méthode. L'itérateur et le listiterateur les retours par ces classes sont rapides (si la liste est structurellement modifiée à tout moment après la création de l'itérateur, de quelque manière que ce soit sauf par les propres méthodes de suppression ou d'ajout de l'itérateur, l'itérateur lancera une exception de modification Concurrentemodificationexception).
quand utiliser LinkedList et quand utiliser ArrayList?
1) comme expliqué ci-dessus, les opérations d'insertion et de suppression donnent de bonnes performances (O(1)) dans LinkedList par rapport à ArrayList(O (n)). Par conséquent, s'il y a une exigence d'ajout et de suppression fréquents dans une application, alors LinkedList est le meilleur choix.
2) les opérations de recherche (méthode get) sont rapides dans ArrayList (O(1)) mais pas dans LinkedList (O(n)) donc S'il y a moins d'opérations d'ajout et de suppression et plus d'opérations de recherche nécessaires, ArrayList serait votre meilleur pari.
Joshua Bloch, l'auteur de LinkedList:
est-ce que quelqu'un utilise réellement LinkedList? Je l'ai écrit, et je ne l'utilise jamais.
lien: https://twitter.com/joshbloch/status/583813919019573248
je suis désolé que la réponse ne soit pas aussi informative que les autres réponses, mais j'ai pensé que ce serait la plus intéressante et explicite.
je sais que c'est un vieux post, mais honnêtement je ne peux pas croire que personne n'a mentionné que LinkedList
met en œuvre Deque
. Il suffit de regarder les méthodes de Deque
(et Queue
); si vous voulez une comparaison équitable, essayez d'exécuter LinkedList
contre ArrayDeque
et de fonctionnalités de comparaison.
si votre code a add(0)
et remove(0)
, utilisez un LinkedList
et c'est plus joli addFirst()
et removeFirst()
méthodes. Sinon, utilisez ArrayList
.
Et bien sûr, Goyave 's ImmutableList est votre meilleur ami.
Voici la notation Big-O dans les deux ArrayList
et LinkedList
et aussi CopyOnWrite-ArrayList
:
ArrayList
get O(1)
add O(1)
contains O(n)
next O(1)
remove O(n)
iterator.remove O(n)
LinkedList
get O(n)
add O(1)
contains O(n)
next O(1)
remove O(1)
iterator.remove O(1)
CopyOnWrite-Liste De Tableaux
get O(1)
add O(n)
contains O(n)
next O(1)
remove O(n)
iterator.remove O(n)
sur la base de ceux-ci, vous devez décider quoi choisir. :)
comparons LinkedList et ArrayList W. R. T. paramètres ci-dessous:
1. La mise en œuvre
ArrayList est le redimensionnable de la matrice de mise en œuvre de la liste de l'interface , alors que
LinkedList est l'implémentation de liste doublement liée de l'interface de liste.
2. Performance
-
get(int index) ou de l'opération de recherche
ArrayList get(int index) operation runs in constant time I. 151910920"
LinkedList get(int index) fonctionnement temps d'exécution est O(n) .
la raison pour laquelle ArrayList est plus rapide que LinkedList est que ArrayList utilise un index basé système pour ses éléments comme il utilise à l'interne une structure de données de tableau, d'autre part,
LinkedList ne fournit pas d'accès par index pour l'un de ses éléments qu'il itère au début ou à la fin (selon la valeur la plus proche) pour récupérer le nœud à l'index de l'élément.
-
insert() ou add(Objet) de l'opération
Insertions LinkedList sont généralement aussi rapides que comparer à ArrayList. Dans LinkedList ajouter ou insérer est O(1) opération .
alors que dans ArrayList , si le tableau est le I. dans le pire des cas, il y a un coût supplémentaire pour redimensionner le tableau et copier des éléments dans le nouveau tableau, ce qui rend l'exécution de l'opération add dans ArrayList O(n), sinon C'est O(1).
-
supprimer(int) opération
Supprimer l'opération dans LinkedList est généralement la même que ArrayList i.e. O(n).
Dans LinkedList , il y a deux surchargé méthodes de suppression. l'un est remove () sans aucun paramètre qui supprime la tête de liste et s'exécute en temps constant O (1). L'autre méthode de suppression surchargée dans LinkedList est remove(int) ou remove (Object) qui supprime L'objet ou int passé en paramètre. Cette méthode traverse l' LinkedList jusqu'à ce qu'il trouve l'objet et le désolidarise de la liste originale. Par conséquent, la durée d'exécution de cette méthode est O(n).
alors que dans ArrayList la méthode remove(int) implique de copier des éléments de l'ancien tableau vers le nouveau tableau mis à jour, donc son exécution est O(n).
3. Itérateur Inversé
LinkedList peut être itéré en sens inverse en utilisant descendingIterator () alors que
il n'y a pas de descendant() dans ArrayList , donc nous avons besoin d'écrire notre propre code pour itérer au-dessus de L'ArrayList en sens inverse.
4. Capacité Initiale
si le constructeur n'est pas surchargé, alors ArrayList crée une liste vide de capacité initiale 10, tandis que
LinkedList ne construit que la liste vide sans aucune capacité initiale.
5. Mémoire Aérienne
surcharge de la Mémoire dans LinkedList est plus par rapport à l'ArrayList comme un nœud dans LinkedList pour maintenir les adresses de la prochaine et nœud précédent. Alors que
dans ArrayList chaque index ne contient que l'objet réel(données).
en plus des autres bons arguments ci-dessus, vous devriez noter ArrayList
met en œuvre RandomAccess
interface, tandis que LinkedList
met en œuvre Queue
.
donc, d'une certaine façon ils abordent des problèmes légèrement différents, avec une différence d'efficacité et de comportement (voir leur liste de méthodes).
une liste de tableaux est essentiellement un tableau avec des méthodes pour ajouter des éléments, etc. (et vous devez utiliser une liste générique à la place). Il s'agit d'un ensemble d'éléments accessibles par l'intermédiaire d'un indexeur (par exemple [0]). Elle implique une progression d'un point à l'autre.
une liste liée spécifie une progression d'un point à l'autre (point a -> point b). Vous pouvez obtenir le même effet avec une liste de tableau, mais une liste liée absolument dit à quel point est censé suivre le précédente.
cela dépend des opérations que vous ferez plus sur la liste.
ArrayList
est plus rapide pour accéder à une valeur indexée. C'est bien pire quand on insère ou supprime des objets.
Pour en savoir plus, lisez l'article qui parle de la différence entre les tableaux et les listes chaînées.
j'ai lu les réponses, mais il y a un scénario où j'utilise toujours une Lienedlist sur un ArrayList que je veux partager pour entendre des opinions:
chaque fois que j'ai eu une méthode qui retourne une liste de données obtenues à partir d'un DB, j'utilise toujours une Likedlist.
mon raisonnement était que parce qu'il est impossible de savoir exactement combien de résultats je reçois, il n'y aura pas de mémoire gaspillée (comme dans ArrayList avec la différence entre la capacité et nombre réel d'éléments), et il n'y aurait pas de temps perdu à essayer de dupliquer la capacité.
en ce qui concerne un ArrayList, je suis d'accord qu'au moins vous devriez toujours utiliser le constructeur avec la capacité initiale, pour minimiser la duplication des tableaux autant que possible.
Une caractéristique importante d'une liste chaînée (que je n'ai pas lu dans une autre réponse) est la concaténation de deux listes. Avec un tableau c'est O(n) (+frais généraux de quelques réallocations) avec une liste liée c'est seulement O(1) ou O (2); -)
Important : pour Java son LinkedList
ce n'est pas vrai! Voir Existe-t-il une méthode de concat rapide pour la liste liée en Java?
L'opération get (i) dans ArrayList est plus rapide que LinkedList, car:
ArrayList: Resizable-array implementation of the List interface
LinkedList: Doubly-linked list implementation of the List and Deque interfaces
opérations qui indexent dans la liste parcourra la liste depuis le début ou la fin, selon la plus proche de l'index spécifié.
ArrayList
et LinkedList
les deux instruments List interface
et leurs méthodes et résultats sont presque identiques. Cependant, il ya quelques différences entre eux qui font mieux sur l'autre en fonction des besoins.
ArrayList Vs LinkedList
1) Search:
ArrayList
l'opération de recherche est assez rapide comparée à l'opération de recherche LinkedList
. get(int index)
dans ArrayList
donne la performance de O(1)
alors que LinkedList
performance est O(n)
.
Reason:
ArrayList
maintient le système basé sur l'index pour ses éléments car il utilise implicitement la structure de données de tableau ce qui le rend plus rapide pour la recherche d'un élément dans la liste. De l'autre côté LinkedList
implémente une liste doublement liée qui nécessite la traversée de tous les éléments pour la recherche d'un élément.
2) Deletion:
LinkedList
enlever l'opération donne O(1)
, tandis que ArrayList
donne des performances variables: O(n)
dans le pire des cas (en enlevant le premier élément) et O(1)
dans le meilleur des cas (en enlevant le dernier élément).
Conclusion: la suppression de L'élément LinkedList est plus rapide que Liste de tableaux.
raison: chaque élément de LinkedList contient deux pointeurs (adresses) qui pointent vers les deux éléments voisins de la liste. D'où la suppression seulement exige le changement dans la position du pointeur dans les deux nœuds voisins (éléments) du noeud qui va être supprimé. Alors que dans ArrayList tous les éléments doivent être décalés pour remplir l'espace créé par l'élément enlevé.
3) Inserts Performance:
LinkedList
la méthode add donne la performance O(1)
tandis que ArrayList
donne la performance O(n)
dans le pire des cas. La raison est la même que celle expliquée pour supprimer.
4) Memory Overhead:
ArrayList
maintient les indices et les données d'élément tandis que LinkedList
maintient les données d'élément et deux pointeurs pour les noeuds voisins
donc la consommation de mémoire est élevée dans LinkedList comparativement.
il y a peu de similitudes entre ces classes qui sont les suivantes:
- les deux tableaux ArrayList et LinkedList sont la mise en œuvre de L'interface de liste.
- ILS deux maintenir l'ordre d'insertion des éléments, ce qui signifie que tout en affichant les éléments ArrayList et LinkedList, le résultat serait d'avoir le même ordre dans lequel les éléments ont été insérés dans la liste.
- ces deux classes sont non-synchronisées et peuvent être synchronisées explicitement en utilisant des Collections.synchronizedList méthode.
- les
iterator
etlistIterator
renvoyés par ces classes sontfail-fast
(si la structure de la liste est modifiée à à tout moment après la création de l'itérateur, de quelque manière que ce soit, sauf par le biais des méthodesiterator’s
propres supprimer ou ajouter, l'itérateur serathrow
aConcurrentModificationException
).
quand utiliser LinkedList et quand utiliser ArrayList?
- comme expliqué ci-dessus, les opérations d'insertion et de suppression donnent de bonnes performances
(O(1))
dansLinkedList
par rapport àArrayList(O(n))
.donc s'il y a une exigence d'ajout et de suppression fréquents dans l'application puis LinkedList est un meilleur choix.
- recherche (
get method
) les opérations sont rapides dansArraylist (O(1))
mais pas dansLinkedList (O(n))
donc S'il y a moins d'opérations add et remove et plus d'opérations de recherche nécessaires, ArrayList serait votre meilleur pari.
ArrayList et LinkedList ont leurs propres avantages et inconvénients.
ArrayList utilise une adresse mémoire contiguë par rapport à LinkedList qui utilise des pointeurs vers le prochain noeud. Ainsi, lorsque vous voulez rechercher un élément dans un ArrayList est plus rapide que de faire n itérations avec LinkedList.
d'un autre côté, l'insertion et la suppression dans une liste de liens sont beaucoup plus faciles parce que vous avez juste à changer les pointeurs tandis qu'un ArrayList implique l'utilisation de opération de déplacement pour toute insertion ou suppression.
si vous avez des opérations de récupération fréquentes dans votre application utilisez un ArrayList. Si vous avez l'insertion et la suppression fréquentes utiliser une liste de liens.
1) Structure De Données Sous-Jacente
la première différence entre ArrayList et LinkedList vient du fait que ArrayList est soutenue par Array tandis que LinkedList est soutenue par LinkedList. Il en résultera d'autres différences de rendement.
2) LinkedList implements Deque
une autre différence entre ArrayList et LinkedList est qu'en dehors de la liste interface, LinkedList implémente également deque interface, qui fournit les premières opérations de sortie pour add() et poll() et plusieurs autres fonctions Deque. 3) Ajouter des éléments dans ArrayList Ajouter un élément dans ArrayList est une opération O(1) si elle ne déclenche pas la re-Taille du tableau, auquel cas elle devient O(log(n)), d'autre part, Ajouter un élément dans LinkedList est une opération O(1), car il ne nécessite pas de navigation.
4) Retrait d'un élément d'un position
afin de supprimer un élément d'un index particulier, par exemple en appelant supprimer(index), ArrayList effectue une opération de copie qui le rend proche de O(n) tandis que LinkedList doit traverser ce point qui le rend également O(n/2), car il peut traverser de l'une ou l'autre direction basée sur la proximité.
5) itération sur ArrayList ou LinkedList
itération est l'opération O(n) pour à la fois LinkedList et ArrayList où n est un nombre d'un élément.
6) Elément récupérant d'une position
l'opération get(index) est O(1) dans ArrayList tandis que son O(n/2) dans LinkedList, car il doit parcourir jusqu'à cette entrée. Cependant, dans la notation Big O O (n / 2) est juste O(n) parce que nous ignorons les constantes là.
7) mémoire
LinkedList utilise un wrapper object, Entry, qui est une classe statique imbriquée pour stocker des données et deux noeuds suivant et précédent tandis que ArrayList stocke juste des données dans Array.
ainsi l'exigence de mémoire semble moindre dans le cas de ArrayList que LinkedList sauf dans le cas où Array effectue l'opération de Re-size quand il copie le contenu d'un Array à un autre.
si le tableau est assez grand il peut prendre beaucoup de mémoire à ce point et déclencher la collecte des ordures, qui peuvent temps de réponse lent.
de toutes les différences ci-dessus entre ArrayList vs LinkedList, il semble que ArrayList est le meilleur choix que LinkedList dans presque tous les cas, sauf quand vous faites une opération fréquente add() que remove(), ou get().
il est plus facile de modifier une liste liée que ArrayList, surtout si vous ajoutez ou supprimez des éléments du début ou de la fin parce que la liste liée garde en interne les références de ces positions et qu'elles sont accessibles en O(1) fois.
en d'autres termes, vous n'avez pas besoin de parcourir la liste liée pour atteindre la position où vous voulez ajouter des éléments, dans ce cas, l'ajout devient O(n) opération. Par exemple, insérer ou supprimer un élément au milieu d'une liste liée.
à mon avis, utiliser ArrayList over LinkedList pour la plupart des fins pratiques en Java.
les systèmes remove() et insert() ont tous deux une efficacité d'exécution O(n) pour les tableaux et les listes reliées. Toutefois, la raison derrière le temps de traitement linéaire vient de deux raisons très différentes:
dans un ArrayList, vous arrivez à L'élément dans O(1), mais en fait enlever ou insérer quelque chose le rend O(n) parce que tous les éléments suivants doivent être changés.
dans une liste de liens, il faut O (n) pour obtenir l'élément désiré, parce que nous devons commencer par le début, jusqu'à ce que nous atteignons l'indice désiré. En fait, supprimer ou insérer est constant, car il suffit de changer 1 référence pour supprimer() et 2 références pour insérer().
lequel des deux est le plus rapide pour insérer et enlever dépend de l'endroit où il se produit. Si nous sommes plus proches du début, la liste de liens sera plus rapide, parce que nous devons passer par relativement peu d'éléments. Si nous sommes plus près de la fin, un ArrayList sera plus rapide., parce que nous y arriver à temps constant et de ne changer que les quelques éléments qui suivent. Lorsqu'elle est faite précisément au milieu, la liste de liens sera plus rapide parce que passer en revue les éléments n est plus rapide que de déplacer les valeurs n.
Bonus: bien qu'il n'y ait aucun moyen de rendre ces deux méthodes O(1) pour un ArrayList, il y a en fait un moyen de le faire dans LinkedLists. Disons que nous voulons passer en revue toute la liste en enlevant et en insérant des éléments sur notre chemin. Habituellement, vous commencerait dès le début pour chaque élément en utilisant la LinkedList, nous pourrions également "enregistrer" l'élément courant sur lequel nous travaillons avec un itérateur. Avec L'aide de L'itérateur, nous obtenons une efficacité O(1) pour remove() et insert() lorsque nous travaillons dans une liste de liens. Ce qui en fait le seul avantage de performance que je connaisse où une LinkedList est toujours meilleure qu'une ArrayList.
ArrayList s'étend AbstractList et met en œuvre la Liste de l'Interface. ArrayList est un réseau dynamique.
On peut dire qu'il a été essentiellement créé pour surmonter les inconvénients de tableaux
La classe LinkedList étend AbstractSequentialList et implémente L'interface List,Deque et Queue.
Performance
arraylist.get()
est O(1) tandis que linkedlist.get()
est O(n)
arraylist.add()
est O(1) et linkedlist.add()
est 0(1)
arraylist.contains()
est O(n) et linkedlist.contains()
est O(n)
arraylist.next()
est O(1) et linkedlist.next()
est O(1)
arraylist.remove()
est O(n) alors que le linkedlist.remove()
est O(1)
Dans arraylist
iterator.remove()
est O(n)
tandis que dans linkedlist
iterator.remove()
est O(1)
L'un des tests que j'ai vu ici ne le fait qu'une seule fois. Mais ce que j'ai remarqué, c'est que vous devez exécuter ces tests plusieurs fois et éventuellement leurs temps convergeront. En gros, la JVM a besoin de se réchauffer. Pour mon cas d'utilisation particulier j'ai besoin d'ajouter/supprimer des éléments d'un dernier qui pousse à environ 500 articles. Dans mes tests, LinkedList
est sorti plus vite, avec LinkedList
lié à environ 50 000 NS et ArrayList
à environ 90 000 NS... donner ou prendre. Voir le code dessous.
public static void main(String[] args) {
List<Long> times = new ArrayList<>();
for (int i = 0; i < 100; i++) {
times.add(doIt());
}
System.out.println("avg = " + (times.stream().mapToLong(x -> x).average()));
}
static long doIt() {
long start = System.nanoTime();
List<Object> list = new LinkedList<>();
//uncomment line below to test with ArrayList
//list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
list.add(i);
}
Iterator it = list.iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
long end = System.nanoTime();
long diff = end - start;
//uncomment to see the JVM warmup and get faster for the first few iterations
//System.out.println(diff)
return diff;
}
Quand dois-je utiliser LinkedList
? Lorsque vous travaillez surtout avec des piles, ou lorsque vous travaillez avec des tampons.
Quand dois-je utiliser ArrayList
? Seulement quand vous travaillez avec des index, sinon vous pouvez utiliser le HashTable avec la liste liée, alors vous obtenez:
table de hachage + liste liée
- accès par clé O (1),
- insérer par la touche O (1),
- supprimer par clé O (1)
- et il y a un truc pour implémenter RemoveAll / SetAll avec O (1) en utilisant versioning
Il semble comme une bonne solution, et dans la plupart des cas, il est, comment jamais vous devez savoir: HashTable prend beaucoup d'espace disque, donc quand vous avez besoin de gérer 1.000.000 liste d'éléments, il peut devenir une chose qui importe. Cela peut se produire dans les implémentations de serveur, chez les clients c'est rarement le cas.
regardez aussi Arbre Rouge-Noir
- accès Aléatoire Log(n),
- insérer Log (n),
- Supprimer Log (n)