Changeset 391 for python/trunk/Doc/library/heapq.rst
- Timestamp:
- Mar 19, 2014, 11:31:01 PM (11 years ago)
- Location:
- python/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
python/trunk
-
Property svn:mergeinfo
set to
/python/vendor/Python-2.7.6 merged eligible /python/vendor/current merged eligible
-
Property svn:mergeinfo
set to
-
python/trunk/Doc/library/heapq.rst
r2 r391 7 7 .. sectionauthor:: Guido van Rossum <guido@python.org> 8 8 .. sectionauthor:: François Pinard 9 .. sectionauthor:: Raymond Hettinger 9 10 10 11 .. versionadded:: 2.3 12 13 **Source code:** :source:`Lib/heapq.py` 14 15 -------------- 11 16 12 17 This module provides an implementation of the heap queue algorithm, also known 13 18 as the priority queue algorithm. 14 19 15 Heaps are arrays for which ``heap[k] <= heap[2*k+1]`` and ``heap[k] <= 16 heap[2*k+2]`` for all *k*, counting elements from zero. For the sake of 17 comparison, non-existing elements are considered to be infinite. The 18 interesting property of a heap is that ``heap[0]`` is always its smallest 19 element. 20 Heaps are binary trees for which every parent node has a value less than or 21 equal to any of its children. This implementation uses arrays for which 22 ``heap[k] <= heap[2*k+1]`` and ``heap[k] <= heap[2*k+2]`` for all *k*, counting 23 elements from zero. For the sake of comparison, non-existing elements are 24 considered to be infinite. The interesting property of a heap is that its 25 smallest element is always the root, ``heap[0]``. 20 26 21 27 The API below differs from textbook heap algorithms in two aspects: (a) We use … … 63 69 Pop and return the smallest item from the *heap*, and also push the new *item*. 64 70 The heap size doesn't change. If the heap is empty, :exc:`IndexError` is raised. 65 This is more efficient than :func:`heappop` followed by :func:`heappush`, and 66 can be more appropriate when using a fixed-size heap. Note that the value 67 returned may be larger than *item*! That constrains reasonable uses of this 68 routine unless written as part of a conditional replacement:: 69 70 if item > heap[0]: 71 item = heapreplace(heap, item) 72 73 Example of use: 74 75 >>> from heapq import heappush, heappop 76 >>> heap = [] 77 >>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] 78 >>> for item in data: 79 ... heappush(heap, item) 80 ... 81 >>> ordered = [] 82 >>> while heap: 83 ... ordered.append(heappop(heap)) 84 ... 85 >>> print ordered 86 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 87 >>> data.sort() 88 >>> print data == ordered 89 True 90 91 Using a heap to insert items at the correct place in a priority queue: 92 93 >>> heap = [] 94 >>> data = [(1, 'J'), (4, 'N'), (3, 'H'), (2, 'O')] 95 >>> for item in data: 96 ... heappush(heap, item) 97 ... 98 >>> while heap: 99 ... print heappop(heap)[1] 100 J 101 O 102 H 103 N 71 72 This one step operation is more efficient than a :func:`heappop` followed by 73 :func:`heappush` and can be more appropriate when using a fixed-size heap. 74 The pop/push combination always returns an element from the heap and replaces 75 it with *item*. 76 77 The value returned may be larger than the *item* added. If that isn't 78 desired, consider using :func:`heappushpop` instead. Its push/pop 79 combination returns the smaller of the two values, leaving the larger value 80 on the heap. 104 81 105 82 … … 152 129 153 130 131 Basic Examples 132 -------------- 133 134 A `heapsort <http://en.wikipedia.org/wiki/Heapsort>`_ can be implemented by 135 pushing all values onto a heap and then popping off the smallest values one at a 136 time:: 137 138 >>> def heapsort(iterable): 139 ... 'Equivalent to sorted(iterable)' 140 ... h = [] 141 ... for value in iterable: 142 ... heappush(h, value) 143 ... return [heappop(h) for i in range(len(h))] 144 ... 145 >>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0]) 146 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 147 148 Heap elements can be tuples. This is useful for assigning comparison values 149 (such as task priorities) alongside the main record being tracked:: 150 151 >>> h = [] 152 >>> heappush(h, (5, 'write code')) 153 >>> heappush(h, (7, 'release product')) 154 >>> heappush(h, (1, 'write spec')) 155 >>> heappush(h, (3, 'create tests')) 156 >>> heappop(h) 157 (1, 'write spec') 158 159 160 Priority Queue Implementation Notes 161 ----------------------------------- 162 163 A `priority queue <http://en.wikipedia.org/wiki/Priority_queue>`_ is common use 164 for a heap, and it presents several implementation challenges: 165 166 * Sort stability: how do you get two tasks with equal priorities to be returned 167 in the order they were originally added? 168 169 * In the future with Python 3, tuple comparison breaks for (priority, task) 170 pairs if the priorities are equal and the tasks do not have a default 171 comparison order. 172 173 * If the priority of a task changes, how do you move it to a new position in 174 the heap? 175 176 * Or if a pending task needs to be deleted, how do you find it and remove it 177 from the queue? 178 179 A solution to the first two challenges is to store entries as 3-element list 180 including the priority, an entry count, and the task. The entry count serves as 181 a tie-breaker so that two tasks with the same priority are returned in the order 182 they were added. And since no two entry counts are the same, the tuple 183 comparison will never attempt to directly compare two tasks. 184 185 The remaining challenges revolve around finding a pending task and making 186 changes to its priority or removing it entirely. Finding a task can be done 187 with a dictionary pointing to an entry in the queue. 188 189 Removing the entry or changing its priority is more difficult because it would 190 break the heap structure invariants. So, a possible solution is to mark the 191 existing entry as removed and add a new entry with the revised priority:: 192 193 pq = [] # list of entries arranged in a heap 194 entry_finder = {} # mapping of tasks to entries 195 REMOVED = '<removed-task>' # placeholder for a removed task 196 counter = itertools.count() # unique sequence count 197 198 def add_task(task, priority=0): 199 'Add a new task or update the priority of an existing task' 200 if task in entry_finder: 201 remove_task(task) 202 count = next(counter) 203 entry = [priority, count, task] 204 entry_finder[task] = entry 205 heappush(pq, entry) 206 207 def remove_task(task): 208 'Mark an existing task as REMOVED. Raise KeyError if not found.' 209 entry = entry_finder.pop(task) 210 entry[-1] = REMOVED 211 212 def pop_task(): 213 'Remove and return the lowest priority task. Raise KeyError if empty.' 214 while pq: 215 priority, count, task = heappop(pq) 216 if task is not REMOVED: 217 del entry_finder[task] 218 return task 219 raise KeyError('pop from an empty priority queue') 220 221 154 222 Theory 155 223 ------ 156 157 (This explanation is due to François Pinard. The Python code for this module158 was contributed by Kevin O'Connor.)159 224 160 225 Heaps are arrays for which ``a[k] <= a[2*k+1]`` and ``a[k] <= a[2*k+2]`` for all … … 196 261 last 0'th element you extracted. This is especially useful in simulation 197 262 contexts, where the tree holds all incoming events, and the "win" condition 198 means the smallest scheduled time. When an event schedule other events for263 means the smallest scheduled time. When an event schedules other events for 199 264 execution, they are scheduled into the future, so they can easily go into the 200 265 heap. So, a heap is a good structure for implementing schedulers (this is what
Note:
See TracChangeset
for help on using the changeset viewer.