mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
# Heap queue algorithm (a.k.a. priority queue)
|
|
def heappush(heap, item):
|
|
"""Push item onto heap, maintaining the heap invariant."""
|
|
heap.append(item)
|
|
_siftdown(heap, 0, len(heap)-1)
|
|
|
|
def heappop(heap):
|
|
"""Pop the smallest item off the heap, maintaining the heap invariant."""
|
|
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
|
|
if heap:
|
|
returnitem = heap[0]
|
|
heap[0] = lastelt
|
|
_siftup(heap, 0)
|
|
return returnitem
|
|
return lastelt
|
|
|
|
def heapreplace(heap, item):
|
|
"""Pop and return the current smallest value, and add the new item.
|
|
|
|
This is more efficient than heappop() followed by heappush(), and can be
|
|
more appropriate when using a fixed-size heap. Note that the value
|
|
returned may be larger than item! That constrains reasonable uses of
|
|
this routine unless written as part of a conditional replacement:
|
|
|
|
if item > heap[0]:
|
|
item = heapreplace(heap, item)
|
|
"""
|
|
returnitem = heap[0] # raises appropriate IndexError if heap is empty
|
|
heap[0] = item
|
|
_siftup(heap, 0)
|
|
return returnitem
|
|
|
|
def heappushpop(heap, item):
|
|
"""Fast version of a heappush followed by a heappop."""
|
|
if heap and heap[0] < item:
|
|
item, heap[0] = heap[0], item
|
|
_siftup(heap, 0)
|
|
return item
|
|
|
|
def heapify(x):
|
|
"""Transform list into a heap, in-place, in O(len(x)) time."""
|
|
n = len(x)
|
|
# Transform bottom-up. The largest index there's any point to looking at
|
|
# is the largest with a child index in-range, so must have 2*i + 1 < n,
|
|
# or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so
|
|
# j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is
|
|
# (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.
|
|
for i in reversed(range(n//2)):
|
|
_siftup(x, i)
|
|
|
|
# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos
|
|
# is the index of a leaf with a possibly out-of-order value. Restore the
|
|
# heap invariant.
|
|
def _siftdown(heap, startpos, pos):
|
|
newitem = heap[pos]
|
|
# Follow the path to the root, moving parents down until finding a place
|
|
# newitem fits.
|
|
while pos > startpos:
|
|
parentpos = (pos - 1) >> 1
|
|
parent = heap[parentpos]
|
|
if newitem < parent:
|
|
heap[pos] = parent
|
|
pos = parentpos
|
|
continue
|
|
break
|
|
heap[pos] = newitem
|
|
|
|
def _siftup(heap, pos):
|
|
endpos = len(heap)
|
|
startpos = pos
|
|
newitem = heap[pos]
|
|
# Bubble up the smaller child until hitting a leaf.
|
|
childpos = 2*pos + 1 # leftmost child position
|
|
while childpos < endpos:
|
|
# Set childpos to index of smaller child.
|
|
rightpos = childpos + 1
|
|
if rightpos < endpos and not heap[childpos] < heap[rightpos]:
|
|
childpos = rightpos
|
|
# Move the smaller child up.
|
|
heap[pos] = heap[childpos]
|
|
pos = childpos
|
|
childpos = 2*pos + 1
|
|
# The leaf at pos is empty now. Put newitem there, and bubble it up
|
|
# to its final resting place (by sifting its parents down).
|
|
heap[pos] = newitem
|
|
_siftdown(heap, startpos, pos) |