这个问题是对这个问题的后续行动: deque.popleft() and list.pop(0). Is there performance difference?
在Python中,我可以使用.pop()
弹出添加到列表中的最后一项。我还可以使用出队和.pop()
弹出最后一项。
这两者之间在性能上有区别吗?是否有理由或用例,一个应该比另一个使用?
编辑:Typo ....将.popright更改为.pop-deque的“ pop right”仍然只是.pop-谢谢ShadowRanger
答案 0 :(得分:2)
list.pop()
是O(1)。它不需要复制任何内容,只需清除最后一个元素并减少列表的长度即可。
双端队列旨在优化从任一端的推送和弹出,因此popleft()
和popright()
均为O(1)。
答案 1 :(得分:2)
首先,pop
和list
都被称为deque
,popright
上没有deque
方法。
通常两者之间没有有意义的性能差异;每隔一段时间,pop
上的deque
会导致块释放(具有固定的开销,这只会使特定的pop
花费更高),并且{ {1}}可能导致重新分配以缩小基础存储(最终可能是list
,但只有O(n)
的一小部分会导致它);渐近地,它们都是pop
运算。如果您的O(1)
确实很大,那么收缩 lot 时,收缩基础存储时可能会偶尔遇到性能问题,但是否则您不太可能注意到差异。>
为回答您的问题,list
的堆栈效率比deque
略高;如果仍然要导入list
,并且需要基于堆栈的结构,则使用collections
会给您带来一点好处(至少在CPython上,不能与其他实现交谈)。但是在这里进行微优化真的不值得。首先导入deque
的成本,以及基于该堆栈执行的任何有用代码的成本,都可能使您在collections
和list
之间看到的微小差异相形见for右边有deque
个。一个简单的pop
微基准测试:
ipython3
因此,对于在我们的堆栈上执行1000次pops之后再进行1000次推入,基于In [24]: %%timeit from collections import deque; s = deque([0] * 10000); onethousandnones = (None,) * 1000; pop = s.pop
...: ; push = s.append
...: for _ in onethousandnones:
...: pop()
...: for _ in onethousandnones:
...: push(0)
...:
...:
104 µs ± 7.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [25]: %%timeit s = [0] * 10000; onethousandnones = (None,) * 1000; pop = s.pop; push = s.append
...: for _ in onethousandnones:
...: pop()
...: for _ in onethousandnones:
...: push(0)
...:
...:
131 µs ± 8.93 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
的堆栈花费的时间减少了30 µs(每次操作减少了约15 ns)。现在可以肯定的是,如果我删除调用括号以计时基本开销,则基本开销约为50 µs,因此,专门归因于deque
的开销是{{1 }},但是在程序可能正在做一些有用的事情的上下文中,它仍然很小,而不仅仅是推送和弹出堆栈。而且无论大小如何,它都相当稳定;对于10倍大小的堆栈,list
和deque
的费用保持不变。如果堆栈增长和缩小得如此之快,以致deque
的摊销增长开始了,那么它可能会因更大的重新分配而遭受更多的损失,但这通常不必担心。
答案 2 :(得分:0)
Python双端队列被实现为双向链表。这导致弹出操作比列表[O(1)]更有效。但是,如果要使用元素的索引访问元素,则列表会更快。