Quand vous add
à la fin d'un ArrayList
il grandira tout seul pour avoir un peu de place. Donc, si vous avez un groupe de dix éléments ArrayList
Si vous ajoutez un élément à la fin, il allouera en interne de l'espace pour vingt éléments, copiera les dix que vous aviez déjà, puis en ajoutera un. Ensuite, lorsque vous ajoutez un autre élément à la fin, il colle simplement ce douzième élément dans l'espace qu'il a déjà créé.
Cela ne lui confère pas techniquement une insertion à temps constant à la fin, mais cela lui donne amorti insertion à temps constant. En d'autres termes, sur un grand nombre d'opérations, le coût se rapproche du temps constant ; à chaque fois qu'il augmente, il double, de sorte que vous disposerez d'un nombre toujours plus grand d'insertions "gratuites" en temps constant avant de devoir à nouveau procéder à un "grow-and-copy".
Lorsque vous insérez au débutant il ne peut pas le faire et doit toujours copier la liste entière dans un nouvel emplacement (temps linéaire).
La suppression de la fin est toujours en temps constant car il suffit de faire passer la dernière cellule de "remplie" à "espace libre". Vous n'avez jamais besoin de copier la liste.
Quant à votre deuxième question, un LinkedList
conserve un pointeur sur la fin de la liste, donc add
y remove
utilisent simplement ce pointeur et sont donc à temps constant. Il n'y a pas de pointeurs rapides au milieu de la liste, donc accéder à un élément arbitraire nécessite une traversée en temps linéaire du début à la fin (potentiellement).