deque.appendleft()是o(1)因基于分块双向链表,仅需指针操作;list.insert(0,x)是o(n)因动态数组需整体右移元素;实测10万次头插,前者耗时约0.012秒,后者约3.4秒,差距近300倍。

deque.appendleft() 为什么是 O(1),而 list.insert(0, x) 是 O(n)
因为底层存储结构完全不同:deque 基于双向链表(更准确说是分块的双向链表),每次 appendleft() 只需新建一个节点、改几个指针;list 是动态数组,insert(0, x) 必须把所有已有元素整体右移一位——元素越多,移动成本越高。
实测性能差距有多大?
在 10 万次头插场景下,典型结果是:
-
list.insert(0, x)耗时约 3.4 秒 -
deque.appendleft(x)耗时约 0.012 秒
差距近 300 倍。这不是常数优化,而是算法复杂度级别的差异——数据量翻 10 倍,list 耗时也几乎翻 10 倍,deque 基本不变。
哪些场景一用 list 就踩坑?
只要涉及高频左端操作,且数据规模不可控,就容易出问题:
- 滑动窗口(如最近 N 条日志、实时指标计算)
- 广度优先搜索(BFS)中维护待访问节点队列
- 撤销栈(undo stack)里频繁
appendleft()新状态 - 网络包缓冲区,按到达顺序头部入、尾部出
这些场景下,哪怕初始数据量小,也可能随运行时间持续增长,list 的延迟会悄然恶化。
maxlen 参数带来的隐性行为
传 maxlen 会让 deque 自动丢弃旧元素,但方向容易混淆:
-
deque([1,2,3], maxlen=2)→ 实际变成deque([2,3], maxlen=2)(右侧进,左侧挤) -
d.appendleft(0)后变成deque([0,2], maxlen=2)(左侧进,右侧挤) - 不设
maxlen时,deque 内部缓冲区可能不缩容——反复popleft()后内存占用未必下降,这是设计使然,不是泄漏
真正要注意的是:maxlen 触发的截断是“被动丢弃”,不会抛异常,也不通知你——它安静地把你最老的数据吞掉。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











