[译]Python - deque双端队列

翻译: 严北,公众号:devintest,转载注明出处:https://www.jianshu.com/p/4ca9b69ade19

class collections.deque([iterable[, maxlen]])

Deque 双端队列介绍

初始化时,传入一个可迭代的数据,将返回一个从左到右的新的deque对象(可以理解为使用append()来遍历并添加数据中的元素到队列右端)。如果没有指定一个初始值,则生成一个长度为0的deque。

双端队列(Deque)是堆栈和队列的一般化(读音是“deck”,是“double-end queue”的缩写)。Deque是线程安全且高效的,从队列两端添加(append)或弹出(pop)元素的复杂度大约仅O(1)

虽然list对象支持类似的操作,但是list的只是对固定长度的列表做优化,在执行改变数据元素位置和列表长度的操作(如pop(0)弹出第一个元素,insert(0,v)在某个位置插入元素)时,复杂度达到O(n)

如果maxlen没有指定或为None,那么deque可以增长到任意长度。否则,deque最大长度将限制为maxlen。一旦一个有界长度的deque被填满,添加新元素时,相应数目的元素就会从相反的一端被丢弃。有界双端队列提供了类似于Unix中的tail过滤器的功能。它们对于跟踪事务和一些数据池也很有用,因为只有最近的活动才是程序关心的。

Deque 对象支持以下方法:

  • append(x)
    将元素 x 添加到队列右端

  • appendleft(x)
    将元素 x 添加到队列左端

  • clear()
    清空队列,并将队列长度置0

  • copy()
    浅复制该队列

Python 3.5 的新特性

  • count(x)
    计算队列中,值等于 x 的个数

Python 3.2 的新特性

  • extend(iterable)
    往队列右端添加可迭代的元素

  • extendleft(iterable)
    往队列右端添加可迭代的元素。需要注意的是,可迭代的元素集将会以倒序形式体现在最终的队列中:

>>> import collections
>>> d = collections.deque()  
>>> d.extendleft(range(6))  
>>> d
deque([5, 4, 3, 2, 1, 0])
  • index(x[, start[, stop]])
    返回元素 x 在队列中的坐标。如果有 start 和 stop 参数,则在以 start 和 stop 为起止索引的子队列中查找该元素 x ,若存在返回元素 x 在完整队列中的坐标。如果元素不在目标队列中,则触发 ValueError 错误

Python 3.5 的新特性

  • insert(i, x)
    将元素 x 插入到队列的 i 位置。
    若插入的位置超过有界双端队列长度,则会触发 IndexError

Python 3.5 的新特性

  • pop()
    弹出(移除并返回)队列最右端的元素。若队列为空,则触发IndexError错误

  • popleft()
    弹出(移除并返回)队列最左端的元素。若队列为空,则触发IndexError错误

  • remove(value)
    移除队列中第一个出现的值为 value 的元素。若不存在这样的元素,则触发ValueError错误

  • reverse()
    反转队列中的元素,并返回None

Python 3.2 的新特性

  • rotate(n=1)
    将deque视为首尾相连的队列,若 n 为正整数,向右移 n 位。n 默认为 1,即当不指定 n 值时,默认右移 1 位。n 可以取负值,表示向左移 n 位:
>>> from collections import deque
>>> d = deque(range(6))
>>> d
deque([0, 1, 2, 3, 4, 5])
>>> d.rotate()    # 向右移1位
>>> d
deque([5, 0, 1, 2, 3, 4])
>>> d.rotate(-3)    # 向左移3位
>>> d
deque([2, 3, 4, 5, 0, 1])

当队列不为空时,右移一位相当于d.appendleft(d.pop()),而左移一位相当于d.append(d.popleft())

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

  • maxlen
    如果队列有界,返回队列最大长度,否则返回None

Python 3.1 的新特性

除了上述的用法,deque同样支持迭代、持久化,能够用 len(d), reversed(d), copy.copy(d), copy.deepcopy(d)等方法,也能用 in 运算符操作deque对象中的元素,以及下标索引例如d[-1]。对两端的索引操作复杂度是O(1),但是当操作中间元素时,复杂度会上升到O(n)。想要快速随机访问队列中的元素,用list更合适。

从 Python 3.5 开始,deque 支持 __add__() (两个deque相加)、__mul__() (deque * n 倍)和 __imul__() (deque * 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'])

应用场景

本节介绍几种deque的具体应用。

有界双端队列提供了一个类似Unix系统下的tail命令功能:

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

deque的另一种使用场景可以是右进左出,用于操作最近添加的几个元素:

这是一个计算相邻几个元素平均值的函数

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 / n

deque的rotate()方法提供了一种切片和删除的方法。举个例子,使用纯Python实现del d[n]功能(将某个位置的元素弹出)依赖于rotate()方法:

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

将需要删除的第 n 位元素用rotate()移至队列最左端,然后用popleft()弹出最左端的这个元素,再将剩下的元素移位回去。

再对这个方法进行一些小改动,还可以很容易地实现Forth语言中对堆栈的操作方法,例如dup, drop, swap, over, pick, rot, 和 roll

翻译自

[1] collections.deque

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343