结论:用 collections.deque 做双端队列比 list 快得多,因其基于双向链表实现,append、pop、appendleft、popleft 均为 O(1);而 list 在头部增删是 O(n),且内存连续易触发 realloc。

直接说结论:用 collections.deque 做双端队列,比用 list 在头尾频繁增删快得多——因为它是基于双向链表实现的,append、pop、appendleft、popleft 全是 O(1);而 list.insert(0, x) 或 list.pop(0) 是 O(n)。
为什么不能直接用 list 模拟双端队列?
看似 list 也能 append() 和 pop(),但一旦涉及左端操作,性能就崩了:
-
list.insert(0, x)需要把所有已有元素右移一位,数据越长越慢 -
list.pop(0)同理,要整体左移,平均移动 n/2 个对象 - 哪怕只做几百次头插,在大数据量(如日志流、滑动窗口)下延迟会明显抬升
- 更隐蔽的问题:
list的内存是连续的,频繁头插还容易触发多次 realloc
deque 的核心方法和参数陷阱
deque 初始化和常用操作都很直白,但几个参数和行为容易误用:
- 初始化时传
maxlen会启用自动截断:超过长度时,新元素从哪边进,就从另一边挤出旧元素(比如append()挤掉最左,appendleft()挤掉最右) -
deque([1,2,3], maxlen=2)→ 实际变成deque([2,3], maxlen=2),不是报错 - 不指定
maxlen就是无界,但要注意它不会自动释放内存——即使你反复popleft(),内部缓冲区可能仍保留空间(这是为了复用,不是内存泄漏) -
deque不支持切片(d[1:3]报TypeError),要用itertools.islice(d, 1, 3)
典型场景下的正确写法示例
比如实现一个固定长度的滑动窗口均值,或 BFS 中的层级遍历:
立即学习“Python免费学习笔记(深入)”;
from collections import deque <h1>✅ 正确:用 popleft() + append() 维护窗口</h1><p>window = deque(maxlen=3) for x in [1, 2, 3, 4, 5]: window.append(x) print(list(window)) # [1], [1,2], [1,2,3], [2,3,4], [3,4,5]</p><h1>✅ BFS 层序遍历时,用 len(queue) 锁定当前层大小</h1><p>queue = deque([root]) while queue: level<em>size = len(queue) # 注意:len(deque) 是 O(1) for </em> in range(level_size): node = queue.popleft() if node.left: queue.append(node.left) if node.right: queue.append(node.right)
别写成 for node in queue: —— 迭代时修改 deque 会导致行为不可靠;也别用 queue[0] 取头再手动 pop(0),那是自废武功。
真正要注意的其实是边界:当 maxlen 被设为 0 或负数时,deque 会接受但后续所有插入都静默失败(不报错,也不存数据);还有多线程环境下,deque 的方法虽是原子的,但复合操作(如先 len(d) 再 d.popleft())仍需加锁——这些细节文档里不显眼,但线上出问题时很难排查。


















