Будет ли LinkedList менее производительным, чем ArrayList, при вставке большого количества элементов в конец в Java?

«Будет ли LinkedList менее производительным, чем ArrayList, при вставке большого количества элементов в конец в Java?» — вопрос из категории Алгоритмы и структуры данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, для операции добавления в конец (addLast/add) их асимптотическая сложность одинакова — O(1). Однако на практике ArrayList часто оказывается быстрее.

Сравнение:

  • LinkedList: Добавление в конец — O(1), так как структура хранит прямые ссылки на голову (head) и хвост (tail). Каждая операция требует создания нового узла (Node), что приводит к накладным расходам на выделение памяти.
  • ArrayList: Добавление в конец — амортизированное O(1). При заполнении внутреннего массива происходит его увеличение (обычно в 1.5-2 раза) и копирование элементов — операция O(n), но она случается редко, что даёт амортизированную константную сложность.

Почему ArrayList часто быстрее на практике:

  1. Локальность данных: Элементы ArrayList хранятся в непрерывном блоке памяти, что эффективно для кэша процессора.
  2. Меньше накладных расходов: ArrayList не создаёт объекты-узлы для каждого элемента.

Пример (псевдотест):

// ArrayList
List<Integer> arrayList = new ArrayList<>();
long start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
    arrayList.add(i); // Амортизированное O(1)
}
System.out.println("ArrayList time: " + (System.nanoTime() - start));

// LinkedList
List<Integer> linkedList = new LinkedList<>();
start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
    linkedList.add(i); // O(1)
}
System.out.println("LinkedList time: " + (System.nanoTime() - start));

Вывод: Для сценария только добавления в конец ArrayList обычно предпочтительнее из-за лучшей производительности в реальных условиях.