我正在寻找一种更有效的方法来重新确定优先级队列中的项目的优先级。我有一个基于heapq
的(非常天真)优先级队列实现。相关部分如下:
from heapq import heapify, heappop
class pq(object):
def __init__(self, init= None):
self.inner, self.item_f= [], {}
if not None is init:
self.inner= [[priority, item] for item, priority in enumerate(init)]
heapify(self.inner)
self.item_f= {pi[1]: pi for pi in self.inner}
def top_one(self):
if not len(self.inner): return None
priority, item= heappop(self.inner)
del self.item_f[item]
return item, priority
def re_prioritize(self, items, prioritizer= lambda x: x+ 1):
for item in items:
if not item in self.item_f: continue
entry= self.item_f[item]
entry[0]= prioritizer(entry[0])
heapify(self.inner)
这是一个简单的协同例程,可以在我的实际应用程序中演示reprioritize特性。
def fecther(priorities, prioritizer= lambda x: x+ 1):
q= pq(priorities)
for k in xrange(len(priorities)+ 1):
items= (yield k, q.top_one())
if not None is items:
q.re_prioritize(items, prioritizer)
通过测试
if __name__ == '__main__':
def gen_tst(n= 3):
priorities= range(n)
priorities.reverse()
priorities= priorities+ range(n)
def tst():
result, f= range(2* n), fecther(priorities)
k, item_t= f.next()
while not None is item_t:
result[k]= item_t[0]
k, item_t= f.send(range(item_t[0]))
return result
return tst
制造
In []: gen_tst()()
Out[]: [2, 3, 4, 5, 1, 0]
In []: t= gen_tst(123)
In []: %timeit t()
10 loops, best of 3: 26 ms per loop
现在,我的问题是,在重新编制优先级队列时,是否存在任何可避免调用heapify(.)
的数据结构?我愿意为了速度交换内存,但应该可以用纯Python实现它(显然比我天真的实现更好的时间)。
更新:
为了让您了解有关特定情况的更多信息,我们假设在初始(批量)推送后没有任何项目添加到队列中,然后队列中的每次提取(弹出)将产生大致类似于此方案的重新编号: / p>
n
,很少n
,通常为n
,很少其中n
是队列中items
的当前数量。因此,在任何一轮中,或多或少只有相对较少的物品要重新制作。所以我希望可能存在一个能够利用这种模式的数据结构,因此在每一轮中都优于执行强制heapify(.)
的成本(为了满足堆不变量)。
更新2 :
到目前为止,似乎heapify(.)
方法确实非常有效(相对而言)。我能够弄清楚的所有替代方案都需要利用heappush(.)
而且它似乎比我原先预期的更昂贵。 (无论如何,如果问题的状态仍然如此,我不得不在python
领域找到更好的解决方案。
答案 0 :(得分:4)
由于新的优先级函数可能与前一个函数没有任何关系,因此您必须支付成本以获得新的排序(并且它至少为O(n)以便找到新排序中的最小元素)。如果你有一个小的,固定数量的优先级函数并经常在它们之间切换,那么你可以从为每个函数保留一个单独的堆中受益(尽管不是与heapq,因为它不支持便宜地定位和删除和对象中间的一堆)。