您的位置:首页 > 其它

5.4.1 使用堆算法实现优级队列

2016-01-17 10:28 274 查看
一个优先级队列通常是使用堆算法来实现,实现优先级队列主要困难有以下几点:

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 深圳
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: