Python 的 deque:比 list 快 100 倍的神奇列表(队列)
python 中,list
是最常用的数据结构之一。当需要频繁在头部或尾部插入、删除元素时,list
可能会变得很慢。
这时候,collections.deque
(双端队列)就该使用这个了deque
。 在某些操作上,它甚至比 list
快 100 倍!
1. 什么是 deque?
deque
(发音 "deck")是 双端队列(Double-Ended Queue) 的缩写。它允许你从两端高效地添加或删除元素,时间复杂度仅为 O(1)。
而 list
在头部操作时,时间复杂度是 O(n),因为它需要移动所有元素。这就是为什么 deque
在特定场景下比 list
快得多!
deque
的基本用法
from collections import deque # 创建一个 deque d = deque([1, 2, 3]) # deque([1, 2, 3]) # 从右侧添加元素 d.append(4) # deque([1, 2, 3, 4]) # 从左侧添加元素 d.appendleft(0) # deque([0, 1, 2, 3, 4]) # 从右侧弹出元素 d.pop() # deque([0, 1, 2, 3]) # 从左侧弹出元素 d.popleft() # deque([1, 2, 3])
2. deque
vs list
:性能对比
测试 1:头部插入(appendleft
和 insert(0, x)
)
import timeit # 测试 deque 的 appendleft def test_deque_appendleft(): d = deque() for i in range(10000): d.appendleft(i) # 测试 list 的 insert(0, x) def test_list_insert(): lst = [] for i in range(10000): lst.insert(0, i) # 测量时间 deque_time = timeit.timeit(test_deque_appendleft, number=1000) list_time = timeit.timeit(test_list_insert, number=1000) print(f"deque.appendleft:{deque_time:.4f}秒") # 输出:0.4435秒 print(f"list.insert(0, x):{list_time:.4f}秒") # 输出:14.7492秒
测试 2:头部删除(popleft
和 pop(0)
)
from collections import deque import timeit def test_deque_popleft(): d = deque(range(10000)) for _ in range(10000): d.popleft() def test_list_pop0(): lst = list(range(10000)) for _ in range(10000): lst.pop(0) deque_time = timeit.timeit(test_deque_popleft, number=1000) list_time = timeit.timeit(test_list_pop0, number=1000) print(f"deque.popleft:{deque_time:.4f}秒") # 输出:0.5152秒 print(f"list.pop(0):{list_time:.4f}秒") # 输出:5.7043秒
3. deque
的进阶用法
(1) 限制队列长度(maxlen)
deque
可以设置最大长度,当队列满时,新元素加入会自动丢弃另一端的元素。
from collections import deque d = deque(maxlen=3) d.append(1) # deque([1]) d.append(2) # deque([1, 2]) d.append(3) # deque([1, 2, 3]) d.append(4) # deque([2, 3, 4]),最左边的 1 被丢弃
适用场景:
- 滑动窗口计算
- 最近 N 条记录存储
(2) 旋转队列(rotate)
rotate(n)
可以让队列循环移动:
rotate(1)
:向右移动 1 位rotate(-1)
:向左移动 1 位
from collections import deque d = deque([1, 2, 3, 4, 5]) d.rotate(2) # deque([4, 5, 1, 2, 3]) d.rotate(-1) # deque([5, 1, 2, 3, 4])
适用场景:
- 轮播数据
- 循环缓冲区
(3) 线程安全(可用于多线程队列)
deque
的 append
、pop
等操作是线程安全的,适合用于多线程任务队列。
from threading import Thread from collections import deque import time queue = deque() def producer(): for i in range(5): queue.append(i) time.sleep(0.1) def consumer(): while True: if queue: print(queue.popleft()) time.sleep(0.1) Thread(target=producer).start() Thread(target=consumer).start()
4. 什么时候用 deque
?什么时候用 list
?
操作 | deque 效率 |
list 效率 |
推荐选择 |
头部插入/删除 | ⚡ O(1) | 🐢 O(n) | ✅ |
deque 尾部插入/删除 |
⚡ O(1) | ⚡ O(1) | 都可以 |
随机访问 | 🐢 O(n) | ⚡ O(1) | ✅ list |
总结:
- 如果需要频繁在头部操作(如队列、栈),用
deque
。 - 如果需要随机访问元素(如
lst[1000]
),用list
。
deque
是 Python 中一个被低估的高性能数据结构。
在需要高效头部操作的场景下,它比 list
快 100 倍!
适用于:
✅ 队列(FIFO)
✅ 栈(LIFO)
✅ 滑动窗口计算
✅ 线程安全任务队列
如果的代码涉及大量 insert(0, x)
或 pop(0)
,就换成 deque