← Назад к вопросам

Что лучше для большого числа операций вставки в середину: ArrayList или LinkedList

2.0 Middle🔥 231 комментариев
#Коллекции#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

ArrayList vs LinkedList для вставок в середину

Краткий ответ

Для большого числа операций вставки в середину LinkedList значительно эффективнее, чем ArrayList. Это связано с их внутренним устройством и сложностью операций.

Почему ArrayList неэффективен

ArrayList использует динамический массив для хранения элементов. Когда вы вставляете элемент в середину списка, необходимо:

  1. Найти позицию вставки — O(1)
  2. Сдвинуть все элементы после позиции на одно место вправо — O(n)
  3. Если массив переполнен, скопировать все элементы в новый массив — O(n)

Таким образом, временная сложность операции add(index, element) — O(n).

ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
    list.add(0, i);  // Каждая вставка требует сдвига всех элементов
    // Сложность: O(n) где n = размер списка
}
// Общая сложность: O(1000²) = O(n²)

Почему LinkedList эффективен

LinkedList основан на двусвязном списке узлов. Каждый узел содержит данные и ссылки на предыдущий и следующий узлы. Вставка требует:

  1. Навигацию к нужной позиции — O(n)
  2. Изменение ссылок в узлах — O(1)
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 1000; i++) {
    list.add(0, i);  // Навигация O(n), вставка O(1)
    // Средняя сложность для начала: O(n)
}
// Общая сложность: O(n²) в худшем случае, но с меньшей константой

Сравнительная таблица

ОперацияArrayListLinkedListПримечание
Добавление в конецO(1)*O(1)*амортизированная
Добавление в началоO(n)O(1)LinkedList выигрывает
Добавление в серединуO(n)O(n)Зависит от позиции
Удаление из серединыO(n)O(n)Зависит от позиции
Доступ по индексуO(1)O(n)ArrayList выигрывает

Практический пример

Пример, демонстрирующий разницу в производительности:

import java.util.*;

public class ListPerformance {
    public static void main(String[] args) {
        testArrayList();
        testLinkedList();
    }
    
    static void testArrayList() {
        ArrayList<Integer> list = new ArrayList<>();
        long start = System.nanoTime();
        
        for (int i = 0; i < 1000; i++) {
            list.add(0, i);  // Вставка в начало
        }
        
        long end = System.nanoTime();
        System.out.println("ArrayList (1000 вставок в начало): " + (end - start) + " ns");
    }
    
    static void testLinkedList() {
        LinkedList<Integer> list = new LinkedList<>();
        long start = System.nanoTime();
        
        for (int i = 0; i < 1000; i++) {
            list.add(0, i);  // Вставка в начало
        }
        
        long end = System.nanoTime();
        System.out.println("LinkedList (1000 вставок в начало): " + (end - start) + " ns");
    }
}

Обычно LinkedList работает в 5-10 раз быстрее на таком тесте.

Рекомендации

  1. LinkedList предпочтителен для частых операций вставки/удаления в начало или середину списка
  2. ArrayList предпочтителен для частого доступа по индексу и добавления в конец
  3. При выборе учитывай профиль использования коллекции
  4. Помни о консумизме памяти — LinkedList требует больше памяти на узлы со ссылками

Итоговый вывод

Для большого числа операций вставки в середину LinkedList — явный победитель. Однако это не универсальное решение: если одновременно требуются частые обращения по индексу, то综合 сложность может быть лучше в ArrayList с переиндексацией или использованием гибридного подхода.