← Назад к вопросам
Какая алгоритмическая сложность вставки объекта в список в Python?
2.0 Middle🔥 181 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Алгоритмическая сложность вставки в список Python
Краткий ответ
Вставка элемента в произвольное место списка — O(n), где n — количество элементов.
Подробное объяснение
1. Вставка в конец (append)
my_list = [1, 2, 3]
my_list.append(4) # O(1) амортизованная сложность
# Python переаллоцирует память только когда нужно
# Обычно переаллокация происходит в 1.125 раза
Сложность: O(1) амортизированная
2. Вставка в начало или середину
my_list = [1, 2, 3, 4, 5]
# Вставка в начало
my_list.insert(0, 0) # [0, 1, 2, 3, 4, 5]
# Нужно сдвинуть все 5 элементов
# Сложность: O(n)
# Вставка в середину
my_list.insert(3, 99) # [0, 1, 2, 99, 3, 4, 5]
# Нужно сдвинуть элементы с индекса 3 до конца (5 элементов)
# Сложность: O(n - i), где i — позиция вставки
# Вставка в конец (явная через insert)
my_list.insert(len(my_list), 100) # [0, 1, 2, 99, 3, 4, 5, 100]
# Сложность: O(1) — не нужно сдвигать элементы
Сложность зависит от позиции:
- В конец: O(1)
- В начало: O(n)
- В позицию i: O(n - i)
Почему O(n)?
Потому что Python хранит список как динамический массив (contiguous memory):
# Внутреннее представление
# [1, 2, 3, 4, 5] <- список в памяти
# 0 1 2 3 4 <- индексы
# При вставке 99 в позицию 2:
my_list = [1, 2, 3, 4, 5]
my_list.insert(2, 99)
# Шаг 1: Найти позицию
# Шаг 2: Сдвинуть элементы [3, 4, 5] на одну позицию вправо
# [1, 2, _, 3, 4, 5] <- нужны O(3) операции
# Шаг 3: Вставить элемент
# [1, 2, 99, 3, 4, 5]
Практический пример с измерением
import timeit
# Вставка в конец (O(1))
setup1 = "lst = list(range(10000))"
stmt1 = "lst.append(99999)"
time1 = timeit.timeit(stmt1, setup1, number=10000)
# Вставка в начало (O(n))
setup2 = "lst = list(range(10000))"
stmt2 = "lst.insert(0, -1)"
time2 = timeit.timeit(stmt2, setup2, number=10000)
print(f"append (O(1)): {time1:.4f}s")
print(f"insert(0) (O(n)): {time2:.4f}s")
print(f"Разница: {time2/time1:.1f}x медленнее")
# Результат: insert примерно в 1000x медленнее!
Сравнение разных операций
import timeit
operation_complexities = {
"append": {"stmt": "lst.append(99)", "complexity": "O(1)"},
"insert(0)": {"stmt": "lst.insert(0, 99)", "complexity": "O(n)"},
"insert(len//2)": {"stmt": "lst.insert(len(lst)//2, 99)", "complexity": "O(n)"},
"extend": {"stmt": "lst.extend([99, 100])", "complexity": "O(k)"},
}
for name, info in operation_complexities.items():
setup = "lst = list(range(10000))"
time = timeit.timeit(info["stmt"], setup, number=1000)
print(f"{name:20} | {info['complexity']:6} | {time:.5f}s")
Таблица сложностей для списка
| Операция | Сложность | Примечание |
|---|---|---|
lst[i] | O(1) | Доступ по индексу |
lst.append(x) | O(1) | Вставка в конец |
lst.insert(0, x) | O(n) | Вставка в начало |
lst.insert(i, x) | O(n-i) | Вставка в позицию i |
lst.pop() | O(1) | Удаление с конца |
lst.pop(0) | O(n) | Удаление с начала |
lst.pop(i) | O(n-i) | Удаление с позиции i |
x in lst | O(n) | Поиск элемента |
lst.remove(x) | O(n) | Удаление по значению |
lst.extend(other) | O(k) | k — длина other |
sorted(lst) | O(n log n) | Сортировка |
Как улучшить производительность
1. Используй deque для вставки в начало
from collections import deque
# Неправильно (O(n))
my_list = [1, 2, 3]
my_list.insert(0, 0) # Медленно
# Правильно (O(1))
my_deque = deque([1, 2, 3])
my_deque.appendleft(0) # Быстро!
# Сравнение
import timeit
list_time = timeit.timeit(
"lst.insert(0, 0)",
"lst = list(range(10000))",
number=1000
)
deque_time = timeit.timeit(
"dq.appendleft(0)",
"from collections import deque; dq = deque(range(10000))",
number=1000
)
print(f"List: {list_time:.4f}s")
print(f"Deque: {deque_time:.4f}s")
print(f"Deque в {list_time/deque_time:.0f}x быстрее")
2. Накопи данные и добавь разом
# Неправильно (O(n*k) где k — количество вставок)
result = []
for i in range(1000):
result.insert(0, i) # O(n) каждый раз!
# Правильно (O(n))
result = []
for i in range(1000):
result.append(i)
result.reverse() # O(n) одна операция
# Или используй deque
from collections import deque
result = deque()
for i in range(1000):
result.appendleft(i) # O(1) каждый раз!
3. Предварительно выдели место
# Если знаешь финальный размер
result = [None] * 1000 # Выдель память один раз
for i in range(1000):
result[i] = i # O(1) присваивание
# Вместо
result = []
for i in range(1000):
result.append(i) # О(1) амортизированная, но может быть переаллокация
Ключевые моменты
- append — O(1) амортизированная
- insert — O(n) в среднем, зависит от позиции
- Причина: Python хранит список как динамический массив
- Решение: Используй
dequeдля вставки в начало - Важно: Избегай циклических insert(0, x) — это O(n²)!