Зачем нужна двусторонняя очередь (deque) и в чём её преимущества?
Разобрался с обычной очередью, но теперь везде вижу слово deque и не до конца понимаю разницу. Если обычная очередь добавляет в конец и забирает из начала, то что особенного в двусторонней? И ещё встретил параметр maxlen — что он делает? Объясните, пожалуйста, в каких реальных задачах deque удобнее обычной очереди или стека.
2 ответа
Отличный вопрос, давай разложу.
Deque (double-ended queue, «дэк») — это очередь, у которой оба конца равноправны: можно добавлять и удалять элементы и спереди, и сзади, причём всё за O(1).
Сравни:
- Обычная очередь (FIFO) — кладём в один конец, берём из другого.
- Стек (LIFO) — кладём и берём с одного конца.
- Deque — умеет и то, и другое одновременно. Это надмножество обеих структур.
В Python это collections.deque:
from collections import deque
d = deque([2, 3])
d.appendleft(1) # в голову -> deque([1, 2, 3])
d.append(4) # в хвост -> deque([1, 2, 3, 4])
d.popleft() # из головы -> 1
d.pop() # из хвоста -> 4
Параметр maxlen задаёт максимальный размер. Когда дек заполнен, добавление с одного конца автоматически выталкивает элемент с противоположного:
history = deque(maxlen=3)
for x in [1, 2, 3, 4, 5]:
history.append(x)
print(history) # deque([3, 4, 5], maxlen=3)
Элементы 1 и 2 «выпали» сами — не нужно вручную следить за размером.
Где deque реально удобнее:
- Скользящее окно (sliding window) — добавляем справа, удаляем слева, обе операции O(1). Классика для задач «максимум в окне».
- История действий / undo-redo, лента последних N событий —
maxlenделает это бесплатно. - Buffer/кольцевой буфер последних логов, последних N запросов.
Итог: бери deque, когда тебе нужен доступ с обоих концов или фиксированный «хвост» последних элементов. Обычный list для этого медленный (вставка в начало — O(n)).
Маленькое, но важное уточнение про сложность: у deque доступ к краям — O(1), а вот обращение к элементу в середине по индексу (d[n//2]) — O(n), в отличие от list, где это O(1).
То есть deque — это инструмент именно для работы с концами. Если тебе нужен частый произвольный доступ по индексу, бери обычный список. Выбор структуры всегда зависит от того, какие операции у тебя в горячем пути.