我的列表结构不断更新。在每次迭代中,都执行以下步骤:
据我了解,这里的堆不是一个好的解决方案(即使使用延迟删除),因为我需要删除列表中某个我不知道其索引(位置)的值。因此,需要搜索这些值。
我是否仅使用排序列表来解决此问题?我需要这里可以达到的最佳性能,因为在循环的某个时刻列表最多包含100.000个元素。
答案 0 :(得分:1)
如果可以将值用作dict键,那么使用堆和collections.Counter
来跟踪概念上仍在集合中的每个值将非常容易。计数为0表示该值在概念上已被完全删除,尽管它可能仍存在于堆中。
这是一个草图(未经测试!),其中c
是collections.Counter
的实例,而h
是用作heapq
模块操作的堆的列表:< / p>
要添加元素(堆大小的预期情况下时间为对数):
heapq.heappush(h, elt)
c[elt] += 1
要删除元素(预期情况下的恒定时间):
if not c[elt]:
raise ValueError("element doesn't exist")
c[elt] -= 1
if not c[elt]:
del c[elt]
要删除最小元素(从堆中弹出的每个概念上已经删除的项目的预期对数时间(以堆的缩小大小为单位)):
while True:
if not h:
raise ValueError("cannot find minimum in empty collection")
elt = heapq.heappop(h)
if c[elt]:
c[elt] -= 1
if not c[elt]:
del c[elt]
break
# else the Counter believes it was deleted earlier
答案 1 :(得分:0)
通过在堆旁边维护一个字典,可以避免不知道要删除的项目的索引的问题。字典中的值与堆项目相同(也许是具有优先级值的列表和对实际项目的引用)。字典键与真实项相同,因此易于查找。
要删除非最小项目时,可以在字典中查找该项目并将其标记为已删除(也许通过将对项目的引用设置为None
)。无需修改表示堆的列表,它具有对相同项目的引用,因此,只要出现要删除的项目,它就会被视为已删除。
也就是说,如果您经常执行“从数据中的任何地方删除项目”操作,那么仅使用常规词典或集合可能会更好。您可以在线性时间内使用min
来获得最小值,并且除去(包括最小项在内的任何项目)都需要固定时间(平均摊销)。对于某些使用模式,可能比处理堆要快。