如何迭代Python中的优先级队列?

时间:2014-09-13 13:57:04

标签: python search

我试图在python中实现Uniform-cost search,为此我需要一个优先级队列,我使用标准库中的queue.py。但是,算法结束时会检查队列中是否存在成本较高的路径。如果我的队列中有任何给定值,如果它不可迭代,我如何检查?

由于

3 个答案:

答案 0 :(得分:5)

queue.PriorityQueue实际上是使用list实现的,put / get方法使用heapq.heappush / heapq.heappop来维护优先级排序在list内。因此,如果您愿意,您可以迭代内部列表,该列表包含在queue属性中:

>>> from queue import PriorityQueue
>>> q = PriorityQueue()
>>> q.put((5, "a"))
>>> q.put((3, "b"))
>>> q.put((25, "c"))
>>> q.put((2, "d"))
>>> print(q.queue)
[(2, 'd'), (3, 'b'), (25, 'c'), (5, 'a')]

答案 1 :(得分:3)

PriorityQueue实现为binary heap,它是在python中使用list(数组)实现的。要遍历队列,您需要知道有关子列表存储在列表中的位置的规则。

规则是所有节点都有两个子节点,除非它们是拥有子节点的最后一个节点,在这种情况下它们可能有一个子节点。在最后一个节点之后出现的所有节点都有零个孩子(duh)。

节点的子节点与节点在列表中的位置相关。其中i是列表中节点的索引,那么它的子节点存储在:

  • 2 * i + 1
  • 2 * i + 2

但是,堆的唯一要求是所有节点的子节点的值都大于或等于节点的值(或者大于取决于实现的值)。

例如,在上面关于binrary heap的链接wiki页面中,您将找到以下图像。队列中的第一项是根。非常明显。第二项是根的子项中较大的一项。但是,第三项可以是根节点的剩余节点,也可以是队列中第二个节点的子节点之一。也就是说,队列(25)中的第三项可能与19或1位于同一位置。

binary heap

因此,要迭代队列,您需要跟踪所有当前“可查看”的节点。例如:

def iter_priority_queue(queue):

    if queue.empty():
        return

    q = queue.queue
    next_indices = [0]
    while next_indices:
        min_index = min(next_indices, key=q.__getitem__)
        yield q[min_index]
        next_indices.remove(mix_index)
        if 2 * min_index + 1 < len(q):
            next_indices.append(2 * min_index + 1)
        if 2 * min_index + 2 < len(q):
            next_indices.append(2 * min_index + 2)

如果您感觉懒惰,可以将方法猴子修补到queue.PriorityQueue,但我鼓励您使用heapq模块实现自己的优先级队列类,因为PriorityQueue来了具有很多过剩功能(主要是线程安全,几乎肯定不需要)。应该注意的是,上述方法线程安全。如果另一个线程在迭代时修改了队列,那么上面的方法将开始产生错误的数字,如果你很幸运,它可能会产生异常。

答案 2 :(得分:1)

除非您需要queue.queue提供的线程安全性,因为它主要用作线程安全作业队列而不是通用队列,您可能最好直接使用collections.deque是可迭代的。