A generic priority queue for Python

后端 未结 12 469
面向向阳花
面向向阳花 2020-12-13 03:27

I need to use a priority queue in my Python code, and:

  • am looking for any fast implementations for priority queues
  • optimally, I\'d li
相关标签:
12条回答
  • 2020-12-13 04:15

    You can use Queue.PriorityQueue.

    Recall that Python isn't strongly typed, so you can save anything you like: just make a tuple of (priority, thing) and you're set.

    0 讨论(0)
  • 2020-12-13 04:16

    I can either use a (priority, object) as Charlie Martin suggests, or just implement __cmp__ for my object.

    If you want inserted objects to be prioritized by a specific rule, I found it very helpful to write a simple subclass of PriorityQueue which accepts a key-function. You won't have to insert (priority, object) tuples manually and the handling feels more natural.

    Demo of the desired behavior:

    >>> h = KeyHeap(sum)
    >>> h.put([-1,1])
    >>> h.put((-1,-2,-3))
    >>> h.put({100})
    >>> h.put([1,2,3])
    >>> h.get()
    (-1, -2, -3)
    >>> h.get()
    [-1, 1]
    >>> h.get()
    [1, 2, 3]
    >>> h.get()
    set([100])
    >>> h.empty()
    True
    >>>
    >>> k = KeyHeap(len)
    >>> k.put('hello')
    >>> k.put('stackoverflow')
    >>> k.put('!')
    >>> k.get()
    '!'
    >>> k.get()
    'hello'
    >>> k.get()
    'stackoverflow'
    

    Python 2 code

    from Queue import PriorityQueue
    
    class KeyHeap(PriorityQueue):
        def __init__(self, key, maxsize=0):            
            PriorityQueue.__init__(self, maxsize)
            self.key = key
    
        def put(self, x):
            PriorityQueue.put(self, (self.key(x), x))
    
        def get(self):
            return PriorityQueue.get(self)[1]
    

    Python 3 code

    from queue import PriorityQueue
    
    class KeyHeap(PriorityQueue):
        def __init__(self, key, maxsize=0):            
            super().__init__(maxsize)
            self.key = key
    
        def put(self, x):
            super().put((self.key(x), x))
    
        def get(self):
            return super().get()[1]
    

    Obviously, calling put will (and should!) raise an error if you try to insert an object which your key-function cannot process.

    0 讨论(0)
  • 2020-12-13 04:20

    I've got a priority queue / fibonacci heap at https://pypi.python.org/pypi/fibonacci-heap-mod

    It's not fast (large constant c on delete-min, which is O(c*logn)). But find-min, insert, decrease-key and merge are all O(1) - IOW, it's lazy.

    If it's too slow on CPython, you might try Pypy, Nuitka or even CPython+Numba :)

    0 讨论(0)
  • 2020-12-13 04:22

    I ended up implementing a wrapper for heapq, adding a dict for maintaining the queue's elements unique. The result should be quite efficient for all operators:

    class PriorityQueueSet(object):
    
        """
        Combined priority queue and set data structure.
    
        Acts like a priority queue, except that its items are guaranteed to be
        unique. Provides O(1) membership test, O(log N) insertion and O(log N)
        removal of the smallest item.
    
        Important: the items of this data structure must be both comparable and
        hashable (i.e. must implement __cmp__ and __hash__). This is true of
        Python's built-in objects, but you should implement those methods if you
        want to use the data structure for custom objects.
        """
    
        def __init__(self, items=[]):
            """
            Create a new PriorityQueueSet.
    
            Arguments:
                items (list): An initial item list - it can be unsorted and
                    non-unique. The data structure will be created in O(N).
            """
            self.set = dict((item, True) for item in items)
            self.heap = self.set.keys()
            heapq.heapify(self.heap)
    
        def has_item(self, item):
            """Check if ``item`` exists in the queue."""
            return item in self.set
    
        def pop_smallest(self):
            """Remove and return the smallest item from the queue."""
            smallest = heapq.heappop(self.heap)
            del self.set[smallest]
            return smallest
    
        def add(self, item):
            """Add ``item`` to the queue if doesn't already exist."""
            if item not in self.set:
                self.set[item] = True
                heapq.heappush(self.heap, item)
    
    0 讨论(0)
  • 2020-12-13 04:22

    You can use heapq for non-integer elements (tuples)

    from heapq import *
    
    heap = []
    data = [(10,"ten"), (3,"three"), (5,"five"), (7,"seven"), (9, "nine"), (2,"two")]
    for item in data:
        heappush(heap, item)
    sorted = []
    while heap:
        sorted.append(heappop(heap))
    print sorted
    data.sort()
    print data == sorted
    
    0 讨论(0)
  • 2020-12-13 04:24

    Did you look at the "Show Source" link on the heapq page? There's an example a little less than halfway down of using a heap with a list of (int, char) tuples as a priority queue.

    0 讨论(0)
提交回复
热议问题