如何从python中通过heapq实现的优先级队列中删除日志(n)中的元素?

如何从python中通过heapq实现的优先级队列中删除日志(n)中的元素?,python,heap,Python,Heap,我已经用python实现了heapq数据结构中的优先级队列。现在我想从保持堆不变量的堆中删除一个特定元素(按值)。 我知道可以通过再次删除元素和heapify()来完成,但这是O(n),而且可能非常慢,因为我有一个非常大的堆 我正在尝试的另一件事是,如果我知道索引,我可以用最后一个元素替换它并完成_shiftup()。 但是因为我不知道索引,我必须搜索,这也是线性时间 我可以保留一个平行的dict指向位置并使用它吗?如何在每次插入队列时更新此类dict 编辑: 实际上,我需要在O(logn)时间

我已经用python实现了heapq数据结构中的优先级队列。现在我想从保持堆不变量的堆中删除一个特定元素(按值)。 我知道可以通过再次删除元素和heapify()来完成,但这是O(n),而且可能非常慢,因为我有一个非常大的堆

我正在尝试的另一件事是,如果我知道索引,我可以用最后一个元素替换它并完成_shiftup()。 但是因为我不知道索引,我必须搜索,这也是线性时间

我可以保留一个平行的dict指向位置并使用它吗?如何在每次插入队列时更新此类dict

编辑:


实际上,我需要在O(logn)时间内实现decreaseKey()。如果有更好的方法直接这样做,那也同样好。

您可能已经读过这篇文章,但可以使用这种方法,即只将元素标记为已删除,而不实际将其从堆中删除:

剩下的挑战围绕着找到一个悬而未决的任务和解决方案 更改其优先级或将其完全删除。寻找任务 可以使用指向队列中条目的字典来完成

删除条目或更改其优先级比较困难,因为 它将打破堆结构不变量。因此,一个可能的解决方案 是将现有条目标记为已删除,并使用 经修订的优先次序:

pq=[]#堆中排列的条目列表
entry_finder={}#任务到条目的映射
已删除=''#已删除任务的占位符
计数器=itertools.count()#唯一序列计数
def add_任务(任务,优先级=0):
'添加新任务或更新现有任务的优先级'
如果条目查找器中有任务:
删除任务(任务)
计数=下一个(计数器)
条目=[优先级、计数、任务]
条目查找器[任务]=条目
堆堆(pq,条目)
def删除_任务(任务):
'将现有任务标记为已删除。如果找不到,则引发KeyError。'
entry=entry\u finder.pop(任务)
条目[-1]=已删除
def pop_任务():
'删除并返回优先级最低的任务。如果为空,则引发KeyError。'
而pq:
优先级、计数、任务=heappop(pq)
如果未删除任务:
del entry_finder[任务]
返回任务
raise KeyError('从空优先级队列弹出')

这样,删除只是dict中的一个
O(1)
查找。删除的项目稍后从队列中弹出时将被忽略(代价是
pop_任务
操作上额外的
O(log n)
)。当然,缺点是,如果客户机实际上没有从队列中弹出项目,堆的大小将增加,即使它的项目根据API被“删除”。

调用它时,删除可能是
O(1)
,但它总共需要
O(logn)
时间。@dano是的,实际上我看到过这种方法,但我想是否还有更好的解决办法。同样,使用这种方法,isEmpty()函数将不会保持O(1),对吗?有什么解决办法吗?@Veedrac是的,谢谢。我在回答中更清楚地说明了这一点。@Naman我不担心isEmpty会变得更贵,因为您所支付的唯一成本是如果您不懒洋洋地进行删除,您会支付的成本。@Naman
条目查找器
dict应该反映队列的真实长度,因为在调用
remove\u task
时会弹出项目。()