|
| 1 | +# Max heap implementation |
| 2 | + |
| 3 | +# runs in linear time |
| 4 | +def heapify(A): |
| 5 | + '''Turns a list `A` into a max-ordered binary heap.''' |
| 6 | + n = len(A) - 1 |
| 7 | + # start at last parent and go left one node at a time |
| 8 | + for node in range(n/2, -1, -1): |
| 9 | + __shiftdown(A, node) |
| 10 | + return |
| 11 | + |
| 12 | +# runs in log(n) time |
| 13 | +def push_heap(A, val): |
| 14 | + '''Pushes a value onto the heap `A` while keeping the heap property |
| 15 | + intact. The heap size increases by 1.''' |
| 16 | + A.append(val) |
| 17 | + __shiftup(A, len(A) - 1) # furthest left node |
| 18 | + return |
| 19 | + |
| 20 | +# runs in log(n) time |
| 21 | +def pop_heap(A): |
| 22 | + '''Returns the max value from the heap `A` while keeping the heap |
| 23 | + property intact. The heap size decreases by 1.''' |
| 24 | + n = len(A) - 1 |
| 25 | + __swap(A, 0, n) |
| 26 | + max = A.pop(n) |
| 27 | + __shiftdown(A, 0) |
| 28 | + return max |
| 29 | + |
| 30 | +# runs in log(n) time |
| 31 | +def replace_key(A, node, newval): |
| 32 | + '''Replace the key at node `node` in the max-heap `A` by `newval`. |
| 33 | + The heap size does not change.''' |
| 34 | + curval = A[node] |
| 35 | + A[node] = newval |
| 36 | + # increase key |
| 37 | + if newval > curval: |
| 38 | + __shiftup(A, node) |
| 39 | + # decrease key |
| 40 | + elif newval < curval: |
| 41 | + __shiftdown(A, node) |
| 42 | + return |
| 43 | + |
| 44 | +def __swap(A, i, j): |
| 45 | + # the pythonic swap |
| 46 | + A[i], A[j] = A[j], A[i] |
| 47 | + return |
| 48 | + |
| 49 | +# runs in log(n) time |
| 50 | +def __shiftdown(A, node): |
| 51 | + '''Traverse down a binary tree `A` starting at node `node` and |
| 52 | + turn it into a max-heap''' |
| 53 | + child = 2*node + 1 |
| 54 | + # base case, stop recursing when we hit the end of the heap |
| 55 | + if child > len(A) - 1: |
| 56 | + return |
| 57 | + # check that second child exists; if so find max |
| 58 | + if (child + 1 <= len(A) - 1) and (A[child+1] > A[child]): |
| 59 | + child += 1 |
| 60 | + # preserves heap structure |
| 61 | + if A[node] < A[child]: |
| 62 | + __swap(A, node, child) |
| 63 | + __shiftdown(A, child) |
| 64 | + else: |
| 65 | + return |
| 66 | + |
| 67 | +# runs in log(n) time |
| 68 | +def __shiftup(A, node): |
| 69 | + '''Traverse up an otherwise max-heap `A` starting at node `node` |
| 70 | + (which is the only node that breaks the heap property) and restore |
| 71 | + the heap structure.''' |
| 72 | + parent = (node - 1)/2 |
| 73 | + if A[parent] < A[node]: |
| 74 | + __swap(A, node, parent) |
| 75 | + # base case; we've reached the top of the heap |
| 76 | + if parent <= 0: |
| 77 | + return |
| 78 | + else: |
| 79 | + __shiftup(A, parent) |
0 commit comments