Python wiki page on time complexity表示删除项目需要花费O(n)时间。 description of the deque class in the documentation of the collections module表示" list
个对象会导致pop(0)
和insert(0, v)
操作的O(n)内存移动成本,从而改变大小和基础数据表示的位置"。
为什么列表需要O(n)时间? Isn列出的只是一堆元素,或指向元素的指针,在内存中彼此物理上相邻,以及指向列表开始位置的指针?如果是这样,为什么list
类型具有popleft
方法,类似于collections.deque
中的方法,通过适当增加来删除O(1)时间内的第一个元素列表的开始指针?
我不是要解决任何具体问题。我只是想满足我的好奇心,为什么它是这样设计的。
编辑:以下是我popleft
方法的工作原理图:
致电popleft
之前:
-------------------------------------------------------------------
| The | quick | brown | fox | jumps | over |
-------------------------------------------------------------------
^
pointer to list
致电popleft
后:
-------------------------------------------------------------------
| The | quick | brown | fox | jumps | over |
-------------------------------------------------------------------
^
pointer to list
在致电popleft
之前,列表的第一个元素是The
,第二个元素是quick
等。通话结束后,第一个元素的位置现在是未使用的内存(可能留空或由垃圾收集器声明),新的第一个元素是quick
,新的第二个元素是brown
等。不需要移动大量数据,并且不需要花费O(n)时间。
答案 0 :(得分:3)
必须保留指向真正列表所在位置的指针,以便正确释放内存。
实际上,通过在这种情况下增加第二个指针可以使remove(0)
更快。如果之后发生.add(0, x)
,只要它大于“内存启动计时器”,就可以通过递减这个“数据启动计时器”来加快速度。
但所有其他操作,我。即对其他索引的插入和删除仍然是O(n)
,因此不会有太大变化。
只需知道您的操作是什么,以及选择哪种数据结构。
答案 1 :(得分:2)
Python list
实际上是一个数组。 deque
是一个真实的链接列表。使用错误的术语是Python的错(我没有解释)。 O(n)
用于插入和删除对于数组是正常的(因为以下元素需要向上或向下移动),这是获取和设置的O(1)
速度的权衡。链接列表在相反的方向上进行类似的权衡:O(1)
用于结束时的操作,但O(n)
用于中间的任何访问。
答案 2 :(得分:1)
没有理由不能,它只是没有。然而,这是代码的复杂性,而您所面临的问题通常表明您采取了错误的方法。
您可以在包装器类中自己实现此行为,并在您知道它值得的情况下使用它。