从 python 中的列表中删除元素

removing element from a list in python

是否有任何方法可以在 O(1) complexity.i 中从 python 中的列表中删除一个元素 complexity.i.e., 删除(值): 这会在列表中线性搜索并正确删除。? 那么,有没有办法通过指定索引或值来删除复杂度为O(1)的元素呢?

当将大小为 100000 的输入列表提供给以下代码时,它超过了时间限制..,即使在使用 "del".

之后
l=map(int,raw_input("").split(" "))
n=l[0]
k=l[1]
s=map(int,raw_input("").split(" "))
s=sorted(s)
count=0
tree=[]
while len(s)>0:
    poset=[]
    indices=[]
    i=0
    poset.append(s[i])
    indices.append(0)
    j=i+1
    while j<len(s):
       if s[j]==k*s[i]:
           poset.append(s[j])
           indices.append(j)
           i=j
        j+=1
    tmp=0
    for i in indices:
        del s[i-tmp]
        tmp+=1                  
    tree.append(poset)

for i in tree:
    if len(i)%2==0:
        count+=(len(i))/2
    else:
        count+=(len(i)+1)/2
print count

正式没有。

如果您知道 C++ Python 列表或多或少地实现为 std::vector 个指向对象的指针(用 C 语言来说,它们是指向连续指针数组的指针)。 这使得 O(1) 可以访问给定索引的元素并允许调整大小,但是从列表中删除一个元素需要将所有后续元素向下移动一个元素以填补空白。

但是请注意,移动的只是指针,无需修复引用计数器即可完成,因此速度非常快(基本上只需一次 memmov 调用)。除非列表很大,否则转移所需的时间非常少。

因此,如果使用 del L[index] 知道索引,则从 Python 中的列表中删除一个元素在形式上是 O(N),但有一个很小的常数因子。

可以实现 list 对象,这样您就可以通过向列表对象添加 "phase" 值来从任一端移除固定时间。这将保持访问 O(1) (具有稍大的常量)但也允许 del L[0] 成为 O(1) 使其类似于 deque.

然而,这已被考虑但未实施,因为它会使 list 对于正常情况的访问更加复杂,并针对具有特定结构的特殊情况进行优化 deque。它还会破坏与任何 C 扩展模块访问列表的兼容性。

有没有办法通过指定索引或值来删除复杂度为O(1)的元素?

如果你知道索引是什么,那么

del L[index]

运行速度非常快(但出人意料的不是 O(1) -- https://www.python.org/dev/peps/pep-3128/#motivation)。如果您只知道该值,那么它可能在任何地方,因此您必须搜索它。平均而言,它必须检查一半的元素,所以这是 O(N)。

其他数据结构可以提供帮助。如果你只想知道不同的元素是什么(而不关心顺序),你可以使用集合。

s = set(['1','b', '1', 'a', 1])
s
s.remove(1)
s

产量输出

{1, '1', 'a', 'b'}
{'1', 'a', 'b'}

并且删除命令(基本上)是 O(1)

打开一个 python 终端(例如 jupyer)并试试这个:

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: del l[0] # O(?)
322 ms ± 1.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = list(range(10000000))
...: del l[0] # O(?)
195 ms ± 1.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: del l[-1] # O(?)
306 ms ± 2.64 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>>: %%timeit
...: l = list(range(10000000))
...: del l[-1] # O(?)
267 ms ± 2.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: l.append(500) # O(1)
299 ms ± 3.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
...: l = list(range(10000000))
...: l.append(500) # O(1)
265 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: max(l) # O(n)
463 ms ± 15.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = list(range(10000000))
...: max(l) # O(n)
335 ms ± 10.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: from collections import deque # lets compare with deque

>>>: %%timeit
...: l = deque(range(10000000))
...: max(l) # O(n)
365 ms ± 1.83 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = deque(range(10000000))
...: l.append(500) #O(1)
283 ms ± 5.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = deque(range(10000000))
...: del l[0]
279 ms ± 2.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = deque(range(10000000))
...: del l[9999999]
286 ms ± 3.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

如您所见,从双端队列中按索引删除项目的复杂度为 O(1),而按索引从列表中删除的复杂度略高,但与其他 O(n) 操作相比仍然相当稳定,例如最大计算量。这与@6502 的回答一致。无论如何,如果您需要使用有向列表初始化程序,差异非常小,因为时间主要由构造过程决定。通过调用实际构造函数进行定向初始化是更可取的。