heapq.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. # Heap queue algorithm (a.k.a. priority queue)
  2. def heappush(heap, item):
  3. """Push item onto heap, maintaining the heap invariant."""
  4. heap.append(item)
  5. _siftdown(heap, 0, len(heap)-1)
  6. def heappop(heap):
  7. """Pop the smallest item off the heap, maintaining the heap invariant."""
  8. lastelt = heap.pop() # raises appropriate IndexError if heap is empty
  9. if heap:
  10. returnitem = heap[0]
  11. heap[0] = lastelt
  12. _siftup(heap, 0)
  13. return returnitem
  14. return lastelt
  15. def heapreplace(heap, item):
  16. """Pop and return the current smallest value, and add the new item.
  17. This is more efficient than heappop() followed by heappush(), and can be
  18. more appropriate when using a fixed-size heap. Note that the value
  19. returned may be larger than item! That constrains reasonable uses of
  20. this routine unless written as part of a conditional replacement:
  21. if item > heap[0]:
  22. item = heapreplace(heap, item)
  23. """
  24. returnitem = heap[0] # raises appropriate IndexError if heap is empty
  25. heap[0] = item
  26. _siftup(heap, 0)
  27. return returnitem
  28. def heappushpop(heap, item):
  29. """Fast version of a heappush followed by a heappop."""
  30. if heap and heap[0] < item:
  31. item, heap[0] = heap[0], item
  32. _siftup(heap, 0)
  33. return item
  34. def heapify(x):
  35. """Transform list into a heap, in-place, in O(len(x)) time."""
  36. n = len(x)
  37. # Transform bottom-up. The largest index there's any point to looking at
  38. # is the largest with a child index in-range, so must have 2*i + 1 < n,
  39. # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so
  40. # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is
  41. # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.
  42. for i in reversed(range(n//2)):
  43. _siftup(x, i)
  44. # 'heap' is a heap at all indices >= startpos, except possibly for pos. pos
  45. # is the index of a leaf with a possibly out-of-order value. Restore the
  46. # heap invariant.
  47. def _siftdown(heap, startpos, pos):
  48. newitem = heap[pos]
  49. # Follow the path to the root, moving parents down until finding a place
  50. # newitem fits.
  51. while pos > startpos:
  52. parentpos = (pos - 1) >> 1
  53. parent = heap[parentpos]
  54. if newitem < parent:
  55. heap[pos] = parent
  56. pos = parentpos
  57. continue
  58. break
  59. heap[pos] = newitem
  60. def _siftup(heap, pos):
  61. endpos = len(heap)
  62. startpos = pos
  63. newitem = heap[pos]
  64. # Bubble up the smaller child until hitting a leaf.
  65. childpos = 2*pos + 1 # leftmost child position
  66. while childpos < endpos:
  67. # Set childpos to index of smaller child.
  68. rightpos = childpos + 1
  69. if rightpos < endpos and not heap[childpos] < heap[rightpos]:
  70. childpos = rightpos
  71. # Move the smaller child up.
  72. heap[pos] = heap[childpos]
  73. pos = childpos
  74. childpos = 2*pos + 1
  75. # The leaf at pos is empty now. Put newitem there, and bubble it up
  76. # to its final resting place (by sifting its parents down).
  77. heap[pos] = newitem
  78. _siftdown(heap, startpos, pos)