← Назад к вопросам
Какая сложность алгоритма вставки в конец ArrayList?
1.0 Junior🔥 201 комментариев
#Коллекции#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Сложность вставки в конец ArrayList
Краткий ответ
Вставка в конец ArrayList:
- В среднем: O(1) amortized (амортизированная сложность)
- В худшем случае: O(n) (когда нужен resize массива)
Как работает ArrayList
ArrayList расширяет свой внутренний массив постепенно. Когда массив переполнен, происходит резкий resize:
public class ArrayList {
private Object[] elementData;
private int size;
public void add(E e) {
ensureCapacity(size + 1);
elementData[size++] = e;
}
private void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length) {
// Увеличиваем примерно на 50%
int newCapacity = (int)(elementData.length * 1.5);
Object[] newArray = new Object[newCapacity];
System.arraycopy(elementData, 0, newArray, 0, size);
elementData = newArray; // O(n) операция!
}
}
}
Анализ по операциям
Обычная вставка (без resize):
arrayList.add(42); // O(1)
Вставка с resize:
// Список на 1000 элементов, попыталась добавить 1001-й
arrayList.add(element); // O(1000) - копирование всех элементов
Амортизированная O(1) сложность
Почему в среднем O(1)? Потому что resize не происходит в каждой операции:
Добавляем элементы:
[1]: O(1) - нет resize
[2]: O(1) - нет resize
[3]: O(1) - нет resize
[4]: O(1) - нет resize
[5]: O(4) - resize! копируем 4 элемента
[6]: O(1) - нет resize
[7]: O(1) - нет resize
[8]: O(1) - нет resize
[9]: O(8) - resize! копируем 8 элементов
...
Общее время для n операций:
O(1 + 1 + 1 + 1 + 4 + 1 + 1 + 1 + 8 + ...) = O(n)
Средняя сложность на одну операцию = O(n) / n = O(1)
Худший случай
ArrayList<Integer> list = new ArrayList<>(1000);
for (int i = 0; i < 1000; i++) {
list.add(i); // O(1) каждый раз
}
list.add(1000); // O(1000) - нужно скопировать все 1000 элементов!
Сравнение со вставкой в начало
// Вставка в конец: O(1) amortized
arrayList.add(element);
// Вставка в начало: O(n)
arrayList.add(0, element); // Нужно сдвинуть все элементы
// Вставка в середину: O(n)
arrayList.add(500, element); // Нужно сдвинуть половину элементов
Практический пример
ArrayList<Integer> list = new ArrayList<>();
long start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
list.add(i); // O(1) amortized
}
long time = System.nanoTime() - start;
System.out.println(time); // примерно 10-50 миллисекунд
// Если бы это был O(n) в каждой операции:
// Времени потребовалось бы: 1000000^2 = 10^12 операций
// Это было бы минуты/часы вычислений!
LinkedList vs ArrayList
// ArrayList: добавление в конец O(1), начало O(n)
arrayList.add(element); // O(1)
arrayList.add(0, element); // O(n)
// LinkedList: добавление везде O(1)
linkedList.add(element); // O(1)
linkedList.add(0, element); // O(1)
Поэтому для добавления в конец ArrayList лучше, а для добавления в начало LinkedList лучше.
Итоговая таблица
| Операция | ArrayList | LinkedList |
|---|---|---|
| add(конец) | O(1) | O(1) |
| add(начало) | O(n) | O(1) |
| add(середина) | O(n) | O(n) |
| get(индекс) | O(1) | O(n) |
| remove(конец) | O(1) | O(1) |
| remove(начало) | O(n) | O(1) |
Вывод
Вставка в конец ArrayList имеет амортизированную O(1) сложность. Это хорошо для использования в качестве динамического массива, но иногда происходят пики в O(n) при resize.