标签:
一个优先级队列通常是使用堆算法来实现,实现优先级队列主要困难有以下几点:
1)排序的稳定性:怎么样实现两个优级一样的任务时返回最先添加的任务?
2)在元组比较里,如果(优先级,任务)对相同时,就没有比较的顺序了。
3)如果一个任务的优先级改变了,你怎么样把它移动到堆的一个新位置上?
4)当任务删除时,你怎么样发现它是删除的,并且把它从堆队列里删除?
为了解决前面两个问题,采用三个元素的列表来实现,这个列表包括:优先级、入口计数、任务。入口计数就是当任务添加时分配一个增加的数字,以便知道任务是添加的顺序,这样就可以解决任务优先级相同时,可以返回最先添加的任务。同时由于入口计数不一样,不用比较到任务,就已经判断出来任务优先顺序了。
剩下来的问题,就是找到未曾执行的任务,并且修改它的优先级,或者完全删除它。查找任务可以通过字典来实现,这个字典保存指向任务列表。删除一个任务或者改变优先级都会让任务队列的堆排序不稳定,因此采用标记的方法来删除,并没有实际删除相关的任务。
例子:
#python 3.4
import heapq
import itertools
pq = [] # 保存堆排序的列表
entry_finder = {} # 保存任务查找的字典
REMOVED = ‘<removed-task>‘ # 任务删除的标记
counter = itertools.count() # 产生任务入口顺序的计数
def add_task(task, priority=0):
‘添加任务或者更新任务的优先级‘
if task in entry_finder:
remove_task(task)
count = next(counter)
entry = [priority, count, task]
entry_finder[task] = entry
heapq.heappush(pq, entry)
def remove_task(task):
‘标记一个存在的任务删除:REMOVED. 如果不存在抛出异常KeyError‘
entry = entry_finder.pop(task)
entry[-1] = REMOVED
def pop_task():
‘删除已经标记删除的任务,并返回最低优先级的任务. 如果不存在抛出KeyError‘
while pq:
priority, count, task = heapq.heappop(pq)
if task is not REMOVED:
del entry_finder[task]
return task
raise KeyError(‘pop from an empty priority queue‘)
add_task(‘abc‘, 5)
add_task(‘b‘, 1)
add_task(‘c‘, 2)
add_task(‘bb‘, 1)
print(pop_task())
print(pop_task())
print(pop_task())
结果输出如下:
b
bb
c
蔡军生 QQ:9073204 深圳
标签:
原文地址:http://blog.csdn.net/caimouse/article/details/50531108