Получить доступ

Чем ArrayList отличается от LinkedList и что брать по умолчанию?

JuniorКоллекции
Ещё спрашивают так:
  • Когда использовать LinkedList?
Коротко

ArrayList — динамический массив: доступ по индексу O(1), добавление в конец амортизированно O(1). LinkedList — двусвязный список: O(1) только при вставке или удалении у уже известного узла. По умолчанию — ArrayList.

  • Поиск позиции в LinkedList — O(n), поэтому add(i, x) линейный у обоих
  • ArrayList компактнее и дружелюбнее к кэшу процессора — почти всегда быстрее на практике
  • Для очереди и стека — ArrayDeque, а не LinkedList

А ещё LinkedList оправдан редко: много вставок через ListIterator в середину огромного списка

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Попробуйте сами

Сколько раз ArrayList копирует массив

Подробно

ArrayList хранит элементы в массиве. get(i) — прямой доступ O(1). add(e) в конец — O(1) амортизированно: когда массив заполнен, он растёт в 1,5 раза с копированием, но копирования редки. Вставка и удаление в середине — O(n): сдвиг хвоста через System.arraycopy (быстрый блочный сдвиг памяти).

LinkedList — двусвязный список узлов {prev, item, next}. get(i) — O(n): обход от ближайшего конца. Вставка и удаление — O(1), если узел уже найден (через ListIterator) или это края списка. add(i, x) по индексу сначала ищет позицию — O(n).

Почему ArrayList почти всегда выигрывает:

  • элементы массива лежат подряд — процессор подгружает их в кэш блоками, а узлы LinkedList разбросаны по куче — промах кэша на каждом шаге;
  • каждый узел — отдельный объект с заголовком и двумя ссылками: в разы больше памяти и работы сборщику;
  • сдвиг массива arraycopy очень быстрый даже на тысячах элементов.

Когда LinkedList: в новом коде — почти никогда. Для очередей и стеков есть ArrayDeque (кольцевой массив). Исключение — частые вставки и удаления в середине при обходе итератором огромного списка, и то стоит измерить.

Что хотят услышать

  • Устройство обеих реализаций.
  • Сложность доступа, вставки в конец и в середину.
  • Почему на практике ArrayList быстрее: кэш и память.
  • ArrayDeque для очередей.

Частые ошибки

  • «LinkedList быстрее для вставки в середину» без учёта поиска позиции.
  • Использовать LinkedList как очередь вместо ArrayDeque.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓ArrayList — массив (индекс O(1)), берут по умолчанию; LinkedList — двусвязный список (индекс O(n)), почти всегда хуже из-за кэша
  • ✗LinkedList быстрее во всём, его и берут по умолчанию
  • ✗ArrayList не умеет расти, LinkedList — динамический
  • ✗Они одинаковы по производительности

Что спросят дальше

  • Как растёт ArrayList при добавлении?
  • Когда LinkedList реально оправдан?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем