|
| 1 | +# Author: ALLSTON MICKEY |
| 2 | +# Contributed: OMKAR PATHAK |
| 3 | +# Created On: 11th August 2017 |
| 4 | + |
| 5 | +from queue import Queue |
| 6 | + |
| 7 | +# min-heap implementation as priority queue |
| 8 | +class Heap(Queue): |
| 9 | + def parent_idx(self, idx): |
| 10 | + return idx // 2 |
| 11 | + |
| 12 | + def left_child_idx(self, idx): |
| 13 | + return (idx * 2) + 1 |
| 14 | + |
| 15 | + def right_child_idx(self, idx): |
| 16 | + return (idx * 2) + 2 |
| 17 | + |
| 18 | + def insert(self, data): |
| 19 | + super().enqueue(data) |
| 20 | + if self.rear >= 1: # heap may need to be fixed |
| 21 | + self.heapify_up() |
| 22 | + |
| 23 | + def heapify_up(self): |
| 24 | + ''' |
| 25 | + Start at the end of the tree (last enqueued item). |
| 26 | +
|
| 27 | + Compare the rear item to its parent, swap if |
| 28 | + the parent is larger than the child (min-heap property). |
| 29 | + Repeat until the min-heap property is met. |
| 30 | + |
| 31 | + Best Case: O(1), item is inserted at correct position, no swaps needed |
| 32 | + Worst Case: O(logn), item needs to be swapped throughout all levels of tree |
| 33 | + ''' |
| 34 | + child = self.rear |
| 35 | + parent = self.parent_idx(child) |
| 36 | + while self.queue[child] < self.queue[self.parent_idx(child)]: |
| 37 | + # Swap (sift up) and update child:parent relation |
| 38 | + self.queue[child], self.queue[parent] = self.queue[parent], self.queue[child] |
| 39 | + child = parent |
| 40 | + parent = self.parent_idx(child) |
| 41 | + |
| 42 | + def pop(self): |
| 43 | + ''' Removes the lowest value element (highest priority, at root) from the heap ''' |
| 44 | + min = super().dequeue() |
| 45 | + if self.rear >= 1: # heap may need to be fixed |
| 46 | + self.heapify_down() |
| 47 | + return min |
| 48 | + |
| 49 | + def favorite(self, parent): |
| 50 | + ''' Determines which child has the highest priority by 3 cases ''' |
| 51 | + left = self.left_child_idx(parent) |
| 52 | + right = self.right_child_idx(parent) |
| 53 | + |
| 54 | + if left <= self.rear and right <= self.rear: # case 1: both nodes exist |
| 55 | + if self.queue[left] <= self.queue[right]: |
| 56 | + return left |
| 57 | + else: |
| 58 | + return right |
| 59 | + elif left <= self.rear: # case 2: only left exists |
| 60 | + return left |
| 61 | + else: # case 3: no children (if left doesn't exist, neither can the right) |
| 62 | + return None |
| 63 | + |
| 64 | + def heapify_down(self): |
| 65 | + ''' |
| 66 | + Select the root and sift down until min-heap property is met. |
| 67 | +
|
| 68 | + While a favorite child exists, and that child is smaller |
| 69 | + than the parent, swap them (sift down). |
| 70 | +
|
| 71 | + Best Case: O(1), item is inserted at correct position, no swaps needed |
| 72 | + Worst Case: O(logn), item needs to be swapped throughout all levels of tree |
| 73 | + ''' |
| 74 | + cur = ROOT = 0 # start at the root |
| 75 | + fav = self.favorite(cur) # determine favorite child |
| 76 | + while self.queue[fav] is not None: |
| 77 | + if self.queue[cur] > self.queue[fav]: |
| 78 | + # Swap (sift down) and update parent:favorite relation |
| 79 | + fav = self.favorite(cur) |
| 80 | + self.queue[cur], self.queue[fav] = self.queue[fav], self.queue[cur] |
| 81 | + cur = fav |
| 82 | + else: |
| 83 | + return |
| 84 | + |
| 85 | + def time_complexities(self): |
| 86 | + return '''[Insert & Pop] Best Case: O(1), Worst Case: O(logn)''' |
| 87 | + |
| 88 | + def get_code(self): |
| 89 | + ''' returns the code for the current class ''' |
| 90 | + import inspect |
| 91 | + return inspect.getsource(Heap) |
0 commit comments