队列——deque(collections)

  • 为什么使用deque?
  • 简述
  • 例子(基础):
  • 其他例子:使用deques的各种方法。


为什么使用deque?

因为需要使用到队列的结构。看了Queue,之后感觉较为复杂,是一个线程安全的队列。
而我如今简单的编程暂时不需要如此复杂的功能。
然后,我发现了简单一些的collections.deque(双端队列)

简述

  • 构造方法class collections.deque([iterable[, maxlen]]):返回一个从左到右初始化的新deque对象(使用append()),其中包含来自iterable的数据。如果未指定iterable,则new deque为空。

Deque是栈/队列结合(双端队列)
Deques是堆栈和队列的泛化(名称读作“deck”,是“双端队列”的缩写)。deque支持线程安全、内存有效的从deque的任何一端追加和弹出,在任何方向上的O(1)性能几乎相同。

使用list操作的缺点
虽然list对象支持类似的操作,但是它们针对快速固定长度的操作进行了优化,会导致pop(0)和insert(0, v)操作带来O(n)内存移动成本,而pop(0)和insert(0, v)操作会改变底层数据表示的大小和位置。

如果未指定maxlen或为None, deques可能会增长到任意长度。否则,deque被限制到指定的最大长度。一旦有界长度deque满了,当添加新项时,将从另一端丢弃相应数量的项。有界长度deques提供了与Unix中的尾部过滤器类似的功能。它们还可用于跟踪仅对最近的活动感兴趣的事务和其他数据池。

使用方法:

  • append(x)
    从右端将x加入到队列。
  • appendleft(x)
    将x添加到队列左端。
  • clear()
    删除所有元素。
  • count(x)
    计算x元素的数量
  • extend(iterable)
    从右端添加一个可迭代中的元素。
  • extendleft(iterable)
    从左端添加一个可迭代的元素。
  • pop()
    删除返回一个右端元素,如果不存在,抛出IndexError.
  • popleft()
    删除返回一个左端元素,如果不存在,抛出IndexError.
  • remove(value)
    删除第一个找到值为value的元素.如果没找到,抛出 ValueError.
  • reverse()
    翻转元素 返回 None.
  • rotate(n=1)
    将队列向右边挪n步,如果n为负数那么往左挪。

当deque不为空时,向右旋转一步等价于d.appendleft(d.pop()),向左旋转一步等价于d.append(d.popleft())。

Deque对象还提供一个只读属性:

  • maxlen:
    deque的最大大小,如果无界则为None。

除此之外,deques还支持迭代、pickle、len(d)、reverse (d)、copy.copy(d)、copy.deepcopy(d)、使用In操作符的成员关系测试以及下标引用,如d[-1]。索引访问在两端都是O(1),但在中间变慢到O(n)。对于快速随机访问,使用列表代替。

例子(基础):

>>> from collections import deque
>>> d = deque('ghi')                 # make a new deque with three items
>>> for elem in d:                   # iterate over the deque's elements
...     print elem.upper()
G
H
I

>>> d.append('j')                    # add a new entry to the right side
>>> d.appendleft('f')                # add a new entry to the left side
>>> d                                # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])

>>> d.pop()                          # return and remove the rightmost item
'j'
>>> d.popleft()                      # return and remove the leftmost item
'f'
>>> list(d)                          # list the contents of the deque
['g', 'h', 'i']
>>> d[0]                             # peek at leftmost item
'g'
>>> d[-1]                            # peek at rightmost item
'i'

>>> list(reversed(d))                # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d                         # search the deque
True
>>> d.extend('jkl')                  # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

>>> deque(reversed(d))               # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # empty the deque
>>> d.pop()                          # cannot pop from an empty deque
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in -toplevel-
    d.pop()
IndexError: pop from an empty deque

>>> d.extendleft('abc')              # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])

其他例子:使用deques的各种方法。

有界长度deque提供的功能类似于Unix中的尾部过滤器:

def tail(filename, n=10):
    'Return the last n lines of a file'
    return deque(open(filename), n)

使用deques的另一种方法是通过向右追加和向左弹出来维护最近添加的元素序列:[还没看懂]

def moving_average(iterable, n=3):
    # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
    # http://en.wikipedia.org/wiki/Moving_average
    it = iter(iterable)
    d = deque(itertools.islice(it, n-1))
    d.appendleft(0)
    s = sum(d)
    for elem in it:
        s += elem - d.popleft()
        d.append(elem)
        yield s / float(n)

rotate()方法提供了一种实现deque切片和删除的方法。例如,del d[n]的纯Python实现依赖于rotate()方法来定位要弹出的元素:

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

要实现deque切片,可以使用类似的方法,应用rotate()将目标元素带到deque的左侧。使用popleft()删除旧条目,使用extend()添加新条目,然后反转旋转。只需对该方法稍加修改,就很容易实现四种样式的堆栈操作,如dup、drop、swap、over、pick、rot和roll。