繁体   English   中英

在Python中从列表开头删除元素便宜吗?

[英]Is removing an element from the front of a list cheap in Python?

我正在编写一个程序,该程序在数据列表的前面或后面进行了大量删除操作,而不是在中间进行删除。

我知道删除最后一个元素很便宜,但是删除第一个元素又如何呢? 例如,假设列表A的地址为4000 ,因此元素04000 ,元素14001

删除元素0然后只是使编译器将列表A的地址放在4001 ,还是将4001元素1移到4000的位置,并将所有其他元素下移1

不,它并不便宜。 从列表的list.pop(0)删除元素list.pop(0)例如,使用list.pop(0) )是O(N)操作, 应避免 同样,在开头插入元素(使用list.insert(0, <value>) )同样效率低下。

这是因为在调整列表大小之后,必须更改其元素。 对于CPython,在l.pop(0)情况下, 这是通过memmove完成的,而对于l.insert(0, <value>)则通过循环存储的项来实现移位

列表是专为快速随机访问O(1)对他们的最终操作。


但是,由于通常是执行此操作,因此应考虑使用collections模块中deque (如@ayhan在评论中建议的那样)。 deque上的文档还强调了list对象不适合这些操作的方式:

尽管列表对象支持类似的操作,但它们针对快速定长操作进行了优化,并且会为pop(0)insert(0, v)操作产生O(n)内存移动成本,这会改变基础数据表示的大小和位置。

(强调我的)

deque数据结构为两侧(开头和结尾)提供O(1)复杂性,分别为appendleft和end使用appendleft / popleftappend / pop方法。

当然,对于较小的列表,这会导致一些额外的空间需求(由于deque的结构),通常不需要考虑(并且正如@juanpa在评论中指出的那样,并不总是如此),因为列表的大小增长。 最后,正如@ShadowRanger富有洞察力的评论所指出的那样,由于序列大小非常小,因此从前面弹出或插入的问题变得无关紧要,以至于实际上变得无关紧要。

简而言之,对于包含很多项目的列表,如果需要从两侧快速添加/弹出,请使用deque ;否则,如果您要随机访问并追加到末尾,请使用list

从Python中的列表开头删除元素是O(n),而从collections的结尾删除元素。deque仅为O(1)。 因此,双端队列对您的目的非常有用,但是应该注意,从双端队列的中间进行访问或添加/删除比列表的开销更大。

删除的O(n)成本是因为CPython中的列表只是实现为一个指针数组,因此您对每个元素的转换成本的直觉是正确的。

这可以在Wiki上的Python TimeComplexity页面中看到。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM