How to iterate over a Priority Queue in Python?

∥☆過路亽.° 提交于 2020-06-14 06:30:50

问题


I'm trying to implement the Uniform-cost search in python and for that I need a priority queue, which I'm using queue.py from the standard library. However, the end of the algorithm checks if there is any path with higher cost in the queue. How can I check if there is any given value in my queue if it's not iterable?

Thanks


回答1:


queue.PriorityQueue is actually implemented using a list, and the put/get methods use heapq.heappush/heapq.heappop to maintain the priority ordering inside that list. So, if you wanted to, you could just iterate over the internal list, which is contained in the queue attribute:

>>> 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')]



回答2:


The PriorityQueue is implemented as binary heap, which is implemented using a list (array) in python. To iterate over the queue you need to know the rules about where children are stored in the list.

The rules being that all nodes have two children, unless they are the last node to have children in which case they may have one child instead. All nodes that appear after the last node to have children will have zero children (duh).

A node's children are stored in relation to the node's own position in the list. Where i is the index of the nodes in the list then it's children are stored at:

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

However, the only requirement of a heap is that all a node's children have a value greater than or equal to the node's value (or greater than depending on the implementation).

For instance, in the above linked wiki page about binrary heap's you'll find the following image. The first item in the queue is the root. Quite obvious. The second item is the larger of the root's children. However, the third item could either be the remaining node of the root node, or either of the children of the second node in the queue. That is, the third item in the queue (25) could have been in the same position as either 19 or 1.

binary heap

Thus, to iterate over the queue you need to keep track of all the currently "viewable" nodes. For instance:

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)

The method can be monkey patched onto queue.PriorityQueue if you're feeling lazy, but I would encourage you to implement your own priority queue class using the heapq module as the PriorityQueue comes with a lot of excess functionality (mainly it is thread safe which almost certainly don't need). It should be noted that the above method is not thread safe. If another thread modifies the queue whilst it is being iterated over then the above method will start yielding the wrong numbers and if you're lucky it may produce an exception.




回答3:


Unless you need the thread safety that queue.queue gives as it was mainly intended as a thread safe job queue and not as a general purpose queue, you might be better off using a collections.deque directly as they are iterable.



来源:https://stackoverflow.com/questions/25823905/how-to-iterate-over-a-priority-queue-in-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!