(1)浅层认知
collections是python内建标准库的集合模块,功能十分强大。
deque是模块中的双向队列对象,其底层逻辑是双向链表。
(2)deque比list更高效
因为采用了双向链表结构,所以可以很方便的塑造「队列」和「栈」,同时成本开销都比list列表要低(时间复杂度和空间复杂度),而且有十分便利的封装方法进行双端操作,几乎与list相关方法名一致、或者在此基础上的拓展。
接下来,我会来论证,如果以后我们要构造队列和栈,为什么要使用deque,而非list。
(3)成本开销
在算法逻辑中,经常会用到队列和栈这两种模型,如果我们用list实现,出队(pop)和插入(insert)时的空间复杂度大约为O(n),deque在出队(pop)和入队(append)时的时间复杂度是O(1)。
为什么?因为链表只需要将指针置空或指向一个新的结点。而,数组都需要把前后的元素整体前移或后移。
(4)双向可操作的封装方法
(4-1)添加元素
(4-1-1)队尾添加元素
仍然是append()。
>>>q=collections.deque([1,2,3,4,5])
>>>q.append(0)
>>>q
(4-1-2)队头添加元素
因为队头在左侧,所以是appendleft()。
>>>q=collections.deque([1,2,3,4,5])
>>>q.appendletf(0)
>>>q
(4-1-3)限制最大长度的添加元素
假如说最多5个元素,当添加第6个元素时,会从另一侧挤掉(溢出)
>>>q=collections.deque([1,2,3,4,5], maxlen=5)
>>>q.append(0)
>>>q
#超过限制长度,队尾增加,队头自动删除
deque([2, 3, 4, 5, 0], maxlen=5)
(4-1-4)插入元素
仍然是insert(插入位置序号,插入的元素值)。
>>>q=collections.deque([1,2,3,4,5])
>>>q.insert(2,7)
>>>q
deque([1, 2, 7, 3, 4, 5])
(4-2)删除操作
(4-2-1)队尾推出元素
仍然是pop()。
同时返回该元素值。
>>>q=collections.deque([1,2,3,4,5])
>>>q.pop()
>>>q
deque([1,2, 3, 4])
(4-2-2)队头推出元素
因为是左侧的推出,保持一致,因此是popleft()。
同时返回该元素值。
>>>q=collections.deque([1,2,3,4,5])
>>>q.popleft()
>>>q
deque([2, 3, 4, 5])
(4-2-3)删除指定元素
remove(元素值)。因为是链表,无直接的序号索引。
>>>q=collections.deque([1,2,3,4,5])
>>>q.remove(2)
>>>q
deque([1, 3, 4, 5])
(4-3)添加序列
(4-3-1)序列创建方法
开始没有讲deque的创建方法,因为是想先对比添加和删除操作与list的异同,接下来,我们来看deque的创建方法,它有两个参数,
- 第2个参数maxlen可以固定队列的最大元素数,前面有应用过;
- 第1个参数,是一个迭代器,如果你把list传进去,它会自动 for in添加每一个元素,实际上就是list转deque,除此以外,无论你放什么,它都会 for in迭代进去,这也是迭代器为什么要叫迭代器的原因,万物皆可for in。
>>>q1=collections.deque()
>>>q2=collections.deque([1,2,3,4,5])
>>>q3=collections.deque("12345")
>>>q4=collections.deque(range(1,6))
>>>q1
>>>q2
>>>q3
>>>q4
deque([])
deque([1, 2, 3, 4, 5])
deque(['1', '2', '3', '4', '5'])
deque([1, 2, 3, 4, 5])
通过观察我们发现,list的表达式是[],而deque没有一对儿专属的符号来表示,它只能是deque([]),从某种意义上讲,deque是不是就是一种特殊的list补集呢?
(4-3-2)队尾添加序列
仍然是extend()。同时,因为传入的参数也是迭代器,可以传入任何可迭代的数据。
>>>q1=collections.deque([1,2,3,4,5])
>>>q2=collections.deque([1,2,3,4,5])
>>>q1.extend([6,7,8])
>>>q2.extend(range(6,10))
>>>q1
>>>q2
deque([1, 2, 3, 4, 5, 6, 7, 8,])
deque([1, 2, 3, 4, 5, 6, 7, 8, 9])
(4-3-3)队头添加元素
因为队头在左侧,所以是extendleft()。
>>>q1=collections.deque([1,2,3,4,5])
>>>q2=collections.deque([1,2,3,4,5])
>>>q1.extendleft([6,7,8])
>>>q2.extendleft(range(6,10))
>>>q1
>>>q2
deque([6, 7, 8, 1, 2, 3, 4, 5])
deque([9, 8, 7, 6, 1, 2, 3, 4, 5])
(5)线程安全
因为是标准库中的封装对象之一,deque是线程安全的,也就是说可以同时从deque集合的左边和右边进行操作而不会有影响。
>>>q=collections.deque([1,2,3,4,5])
>>>q.append(q.popleft())
>>>q
deque([2, 3, 4, 5, 1])