list.pop()和deque.pop()-在性能上有区别吗?

时间:2019-08-09 23:59:58

标签: python

这个问题是对这个问题的后续行动: deque.popleft() and list.pop(0). Is there performance difference?

在Python中,我可以使用.pop()弹出添加到列表中的最后一项。我还可以使用出队和.pop()弹出最后一项。

这两者之间在性能上有区别吗?是否有理由或用例,一个应该比另一个使用?

编辑:Typo ....将.popright更改为.pop-deque的“ pop right”仍然只是.pop-谢谢ShadowRanger

3 个答案:

答案 0 :(得分:2)

list.pop()是O(1)。它不需要复制任何内容,只需清除最后一个元素并减少列表的长度即可。

双端队列旨在优化从任一端的推送和弹出,因此popleft()popright()均为O(1)。

答案 1 :(得分:2)

首先,poplist都被称为dequepopright上没有deque方法。

通常两者之间没有有意义的性能差异;每隔一段时间,pop上的deque会导致块释放(具有固定的开销,这只会使特定的pop花费更高),并且{ {1}}可能导致重新分配以缩小基础存储(最终可能是list,但只有O(n)的一小部分会导致它);渐近地,它们都是pop运算。如果您的O(1)确实很大,那么收缩 lot 时,收缩基础存储时可能会偶尔遇到性能问题,但是否则您不太可能注意到差异。

为回答您的问题,list的堆栈效率比deque略高;如果仍然要导入list,并且需要基于堆栈的结构,则使用collections会给您带来一点好处(至少在CPython上,不能与其他实现交谈)。但是在这里进行微优化真的不值得。首先导入deque的成本,以及基于该堆栈执行的任何有用代码的成本,都可能使您在collectionslist之间看到的微小差异相形见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倍大小的堆栈,listdeque的费用保持不变。如果堆栈增长和缩小得如此之快,以致deque的摊销增长开始了,那么它可能会因更大的重新分配而遭受更多的损失,但这通常不必担心。

答案 2 :(得分:0)

Python双端队列被实现为双向链表。这导致弹出操作比列表[O(1)]更有效。但是,如果要使用元素的索引访问元素,则列表会更快。

相关问题