6

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 a higher cost in the queue. How can I check if there is any given value in my queue if it's not iterable?

Rodrigo Souza
  • 7,162
  • 12
  • 41
  • 72
  • I'd recommend writing your own priority queue using simple a simple `list` and `heapq`. It's not that bad. See the [implementation notes](https://docs.python.org/2/library/heapq.html#priority-queue-implementation-notes) in the heapq docs. – roippi Sep 13 '14 at 14:25
  • @roippi That's exactly how `queue.PriorityQueue` is implemented :) – dano Sep 13 '14 at 16:27

4 Answers4

14

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')]
Phrogz
  • 296,393
  • 112
  • 651
  • 745
dano
  • 91,354
  • 19
  • 222
  • 219
  • The first line should be: from Queue import PriorityQueue. Note the capital Q. – Sushil Verma Jul 08 '17 at 09:43
  • @SushilVerma Yes, for Python 2. In Python 3.x, it's a lowercase q. – dano Jul 08 '17 at 12:41
  • As my good friend [T. Payne](https://github.com/TPayneExperience) showed in one of his videos: ` try: import queue as Queue except: import Queue <\blink> And you're covered for both – WaveRider Sep 17 '17 at 20:56
6

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.

Dunes
  • 37,291
  • 7
  • 81
  • 97
1

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.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
0

If you want a sorted list from priority que, you can try this.

que = PriorityQueue()
que.put(item1)
que.put(item2)
que.put(item3)

sorted_list = [] 
while que.empty()  == False:
    sorted_list.append(que.get())