什么是deque deque
即队列队列的一种 — 双端队列(double-ended queue的缩写),是一种数据结构,它允许你在队列的两端进行添加(append)和弹出(pop)操作。
队列是操作受限的线性表,只允许在一端进行插入 (入队),另一端进行删除 (出队)
操作特性:先进先出 FIFO
队头(Front):允许删除的一端
队尾(Rear):允许插入的一端
空队列:不含任何元素的空表
而双端队列就是在队列的基础上,两边都可以作对头和队尾。
Python中deque
和列表有很多相似地方,基本使用非常类似。
如何实现 创建 1 2 3 4 5 6 7 from collections import dequenew_deque = deque() print (new_deque) new_deque.clear()
在创建队列时,我们可以将其他可迭代对象,迭代元素作为队列的元素,怎么理解呢?
队列的形式是deque([])
,假如初始化时,里面是一个可迭代对象,那么队列会讲可迭代元素作为他的初始元素,这一点类似 解包然后打包,可以通过如下例子看一下
1 2 3 4 5 6 7 new_deque = deque("hello" ) print (new_deque) new_deque.clear() new_deque = deque(["hello" ]) print (new_deque) new_deque.clear()
增删改查等操作 增删改查操作和列表基本一模一样,列表可以用的许多基本方法deque
也可以使用(注意:队列没法切片),这里举例说明.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 ''' 从下面的操作结果,我们可以看出,队列和列表一样,增加元素都是默认增加在右边的,而且append的操作完全一致 ''' new_deque = deque() new_deque.append("first element" ) new_deque.append("second element" ) new_deque.append(["first list" ]) print (new_deque)'''队列有一种类型叫做双端队列,顾名思义,两端都可以执行入队出队操作,因此实际上我们也可以从左边执行入队操作''' new_deque.clear() new_deque.appendleft("first element" ) new_deque.appendleft("second element" ) new_deque.appendleft(["first list" ]) print (new_deque)new_deque.clear() '''deque 和 list 一样,同样的也支持使用 extend 将「可迭代对象」的所有元素都依次添加进队列,和append类似,extend也可以从左边入队,即 extendleft''' l1 = [1 , 2 , 3 , 4 ] l2 = [5 , 6 , 7 , 8 ] l3 = [0 , -1 , -2 , -3 ] new_deque = deque(l1) print (new_deque)new_deque.extend(l2) print (new_deque)new_deque.extendleft(l3) print (new_deque)'''队列的出队操作使用的方法也是 pop(),当然和入队操作一样,出队可以双端执行,默认也是从右端出队,可以通过如下示例理解''' de = deque([1 , 2 , 3 , 4 , 5 , 6 , 7 ]) print (de.pop()) print (de.popleft()) ''' 此外,队列支持许多列表中的方法,如下所示 * count(x) 计算元素x出现的次数 * index(x) - 查找出现给定值x的第一个位置 * remove(x) - 删除第一个x出现的值 * reverse() - 就地反转 deque 同时,还有一个列表不支持的方法 --- rotate() 旋转,该方法如果理解循环队列就知道其作用了,就是让队列整个转一个元素 ''' rotate_deque = deque([1 , 2 , 3 , 4 ]) rotate_deque.rotate() print (rotate_deque)'''rotate()默认参数 1 ,即顺时针旋转一个元素,我们可以修改参数来控制旋转的方向和旋转长度''' rotate_deque.rotate(2 ) print (rotate_deque)rotate_deque.rotate(-3 ) print (rotate_deque)
deque与list的区别 方法上的区别主要就是上面说的left
以及旋转,这些都是针对队列特性做出的适应,队列的先进先出特性、双端队列、循环队列都可以实现。
从上面来看,队列的操作基本和列表一致,但是如果仅是如此的话,列表实现上述功能也是可以的,列表可以使用「切片」操作啊,那么队列的优势在哪 ?
在deque
中,可以从左侧有效地追加和弹出元素(而在列表中,随着列表的增长,追加和弹出元素的速度会变慢)
在 deque
中,可以通过参数 maxlen
控制deque
的最大尺寸 — 这一特性可以帮我们实现一些特殊操作
1 2 3 4 5 6 7 8 9 10 '''当队列中的元素已经达到 maxlen 时,此时再向其中添加元素,则会把先进去的元素挤出去 --- 先进先出特性''' deque_size = 3 deque_max = deque([1 , 2 , 3 ], maxlen=deque_size) print (deque_max)deque_max.append(4 ) print (deque_max)'''如上所示,元素 4 将元素 1 挤出了队列'''
这一特性,在实践中非常有用 — 滑动窗口 、缓冲区、历史记录 — 利用队列的「先进先出」特性
在处理数据流或时间序列时,你可能需要考虑一个固定大小的滑动窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 ‘‘‘ 计算最近 n 个数据点的平均值 ’’’ from collections import dequewindow_size = 5 window = deque(maxlen=window_size) for data_point in data_stream: window.append(data_point) print (f"Current rolling average: {sum (window) / len (window)} " )
由于使用的是生成器表达式和一次只能容纳一个元素的 deque
,这意味着您尽可能地节省了空间,这种方法应用到大文件中处理数据 时,在空间上的效率就会非常方便
1 2 3 4 5 6 7 8 9 10 11 12 13 from collections import dequesentence = "The quick brown fox jumps over the last dog!" vowels = set ("aeiouAEIOU" ) last_vowel = deque((char for char in sentence if char in vowels), maxlen=1 ) try : print (last_vowel.pop()) except IndexError: print ("No vowels found." )
在实现网络协议或处理I/O操作时,maxlen
可以作为一个缓冲区大小的限制 ,历史记录也是同理,存放一定数目的记录,越先记录的越先被删除
1 2 3 4 5 buffer = deque(maxlen=1024 ) while receiving_data: buffer.append(new_data)
更多的例子可以看deque
教程 这篇文章的最后一节。
reference
deque 教程
官方文档