使用Python中的堆创建优先级队列

时间:2018-10-05 20:56:19

标签: python-2.7 heap priority-queue

我是Python的新手,所以请为愚蠢的错误辩解... 我正在尝试使用python(2.7.15)中的堆创建优先级队列,但是我的代码显然无法正常工作。

pq = []                         # list of entries arranged in a heap
entry_finder = {}               # mapping of tasks to entries
REMOVED = '<removed-task>'      # placeholder for a removed task
count = 0     # unique sequence count

def push(pq,task,priority=0):
    'Add a new task'
    count = count+1
    entry = [priority, count, task]
    entry_finder[task] = entry
    heappush(pq, entry)

def update(pq,task, priority=0):
    'Add a new task or update the priority of an existing task'
    if task in entry_finder:
        remove_task(task)
    count = count+1
    entry = [priority, count, task]
    entry_finder[task] = entry
    heappush(pq, entry)

def remove_task(task):
    'Mark an existing task as REMOVED.  Raise KeyError if not found.'
    entry = entry_finder.pop(task)
    entry[-1] = REMOVED

def pop(pq):
    'Remove and return the lowest priority task. Raise KeyError if empty.'
    while pq:
        priority, count, task = heappop(pq)
        if task is not REMOVED:
            del entry_finder[task]
            return task
    raise KeyError('pop from an empty priority queue')

def IsEmpty(pq):
    if not pq:
    print("List is empty")

这就是我所做的,其中大多数都被放在这里:https://docs.python.org/2/library/heapq.html。 我的问题是当我尝试在python interprenter上运行它时,我得到了:

>>> pq=[]
>>> pq.push("task1",1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'push'

我的问题是我该怎么做才能避免此错误,并且我的代码是否存在可能导致进一步错误的缺陷?

2 个答案:

答案 0 :(得分:1)

您正在以“面向对象的C”样式构建类,该类涉及将对象上下文传递到函数中,例如do_something(instance, arg)。这是可行的,但对Python来说不​​是自然的,Python支持类和一个名为self的关键字,该关键字代表对象的实例,允许您像调用{{ 1}}功能。

使用这种方法,一个类将封装您当前在全局范围内拥有的所有状态数据:

instance.do_something(arg)

即使以“ C”样式编写,程序在这些全局变量之外也没有实例状态;您需要某种结构来将这些变量保持在一起并将它们传递给函数,或者对每个函数中的每个变量使用push关键字,这在状态安全方面不是一个很好的解决方案,可重用性,可理解性或任何其他设计指标。

以下是该程序重构为类的示例:

pq = []                         # list of entries arranged in a heap
entry_finder = {}               # mapping of tasks to entries
REMOVED = '<removed-task>'      # placeholder for a removed task
count = 0                       # unique sequence count

完成此操作后,您现在可以将类导入到解释器中(确保源代码位于同一文件夹global中),创建该类的实例并开始使用它:

from heapq import heappush, heappop


class PQ:
    def __init__(self):
        self.pq = []
        self.entry_finder = {}
        self.REMOVED = '<removed-task>'
        self.count = 0

    def push(self, task, priority=0):
        '''Add a new task
        '''
        self.count += 1
        entry = [priority, self.count, task]
        self.entry_finder[task] = entry
        heappush(self.pq, entry)

    def update(self, task, priority=0):
        '''Add a new task or update the priority of an existing task
        '''
        if task in self.entry_finder:
            self.remove_task(task)

        self.count += 1
        entry = [priority, self.count, task]
        self.entry_finder[task] = entry
        heappush(self.pq, entry)

    def remove_task(self, task):
        '''Mark an existing task as REMOVED.  Raise KeyError if not found.
        '''
        entry = self.entry_finder.pop(task)
        entry[-1] = self.REMOVED

    def pop(self):
        '''Remove and return the lowest priority task. Raise KeyError if empty.
        '''
        while self.pq:
            priority, count, task = heappop(self.pq)

            if task is not self.REMOVED:
                del self.entry_finder[task]
                return task

        raise KeyError('pop from an empty priority queue')

    def empty(self):
        return len(self.pq) == 0

另一种常见的做法是使用pq.py条件:直接将测试添加到类文件中:

>>> from pq import PQ
>>> pq = PQ()
>>> pq.push(1, 20)
>>> pq.push(2, 30)
>>> pq.push(3, 10)
>>> while not pq.empty(): print pq.pop()
...
3
1
2
>>>

这可以在带有if __name__ == '__main__':的终端上运行。

Try it!

答案 1 :(得分:0)

定义push函数的方式,您需要将代表队列的列表作为第一个参数传递:

代替

pq = []
pq.push("task1", 1)

pq = []
push(pq, "task1", 1)