@@ -28,3 +28,101 @@ def replace(self, item):
2828
2929 def peek (self ):
3030 return self ._items [0 ]
31+
32+
33+ class PriorityQueue :
34+ """Priority queue implemented using a heap.
35+
36+ This implementation ensures stability: items with the same priority
37+ are returned in the order they were added, and the values of the
38+ items themselves are never compared.
39+
40+ >>> q = PriorityQueue()
41+ >>> q.push('lmao')
42+ >>> q.push('ayy', priority=1)
43+ >>> while q:
44+ ... print(q.pop())
45+ ayy
46+ lmao
47+
48+ The queue may be destructively iterated over:
49+
50+ >>> q.push('ayy')
51+ >>> q.push('lmao')
52+ >>> len(q), list(q)
53+ (2, ['ayy', 'lmao'])
54+ >>> len(q), list(q)
55+ (0, [])
56+
57+ """
58+
59+ def __init__ (self , items = None ):
60+ from itertools import count
61+ self ._heap = []
62+ self ._counter = count ()
63+
64+ def push (self , item , priority = 0 ):
65+ from heapq import heappush
66+ # Entries are stored as tuples, which heapq compares when they
67+ # are pushed or popped. The priority and a unique ID are stored
68+ # as the first two elements to make sure the item itself is
69+ # never included in any comparison.
70+ #
71+ # The heapq module implements a min-heap, so invert the priority
72+ # and make the IDs monotonically increase to ensure stability.
73+ heappush (self ._heap , (- priority , next (self ._counter ), item ))
74+
75+ def pop (self ):
76+ from heapq import heappop
77+ _ , _ , item = heappop (self ._heap )
78+ return item
79+
80+ def peek (self ):
81+ """
82+ >>> q = PriorityQueue()
83+ >>> q.peek()
84+ Traceback (most recent call last):
85+ ...
86+ IndexError: list index out of range
87+ >>> q.push(None)
88+ >>> q.peek()
89+ """
90+ _ , _ , item = self ._heap [0 ]
91+ return item
92+
93+ def __bool__ (self ):
94+ """
95+ >>> q = PriorityQueue()
96+ >>> bool(q)
97+ False
98+ >>> q.push(None)
99+ >>> bool(q)
100+ True
101+ >>> q.pop()
102+ >>> bool(q)
103+ False
104+ """
105+ return bool (self ._heap )
106+
107+ def __len__ (self ):
108+ """
109+ >>> q = PriorityQueue()
110+ >>> len(q)
111+ 0
112+ >>> q.push(None)
113+ >>> len(q)
114+ 1
115+ >>> q.pop()
116+ >>> len(q)
117+ 0
118+ """
119+ return len (self ._heap )
120+
121+ def __next__ (self ):
122+ try :
123+ return self .pop ()
124+ except IndexError :
125+ raise StopIteration
126+
127+ def __iter__ (self ):
128+ return self
0 commit comments