diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index 37dfdde..03d5918 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -6,9 +6,9 @@ Congratulations! You're submitting your assignment! Question | Answer :------------- | :------------- -How is a Heap different from a Binary Search Tree? | -Could you build a heap with linked nodes? | -Why is adding a node to a heap an O(log n) operation? | -Were the `heap_up` & `heap_down` methods useful? Why? | +How is a Heap different from a Binary Search Tree? | Heaps are unordered +Could you build a heap with linked nodes? | No +Why is adding a node to a heap an O(log n) operation? | Because you only need to iterate half of the tree +Were the `heap_up` & `heap_down` methods useful? Why? | Yes. heap_up checks if a node needs to move up and swap when necessary. heap_down removes a node at the root and replace the respective child upward. diff --git a/heaps/heap_sort.py b/heaps/heap_sort.py index 3b834a5..df5d076 100644 --- a/heaps/heap_sort.py +++ b/heaps/heap_sort.py @@ -1,8 +1,20 @@ +from heaps.min_heap import MinHeap def heap_sort(list): """ This method uses a heap to sort an array. - Time Complexity: ? - Space Complexity: ? + Time Complexity: O(n log n)? + Space Complexity: O(n)? """ - pass \ No newline at end of file + + heap = MinHeap() + + for num in list: + heap.add(num) + + index = 0 + while not heap.empty(): + list[index] = heap.remove() + index += 1 + + return list diff --git a/heaps/min_heap.py b/heaps/min_heap.py index f6fe4e0..a2de647 100644 --- a/heaps/min_heap.py +++ b/heaps/min_heap.py @@ -1,5 +1,5 @@ class HeapNode: - + def __init__(self, key, value): self.key = key self.value = value @@ -10,30 +10,44 @@ def __str__(self): def __repr__(self): return str(self.value) + class MinHeap: def __init__(self): self.store = [] - - def add(self, key, value = None): + def add(self, key, value=None): """ This method adds a HeapNode instance to the heap If value == None the new node's value should be set to key - Time Complexity: ? - Space Complexity: ? + Time Complexity: O(log n)? + Space Complexity: O(log n)? (the recursive stack space, if done iteratively it's constant space) """ - pass + if value == None: + value = key + + node = HeapNode(key, value) + self.store.append(node) + self.heap_up(len(self.store) - 1) def remove(self): """ This method removes and returns an element from the heap maintaining the heap structure - Time Complexity: ? - Space Complexity: ? + Time Complexity: O(log n)? + Space Complexity: O(log n)? """ - pass + # Now pull up the next item from below + # be sure to clear out the last item in the array + + if self.empty(): + return None + + self.swap(0, len(self.store) - 1) + remove = self.store.pop() + + self.heap_down(0) + return remove.value - def __str__(self): """ This method lets you print the heap, when you're testing your app. """ @@ -41,26 +55,32 @@ def __str__(self): return "[]" return f"[{', '.join([str(element) for element in self.store])}]" - def empty(self): """ This method returns true if the heap is empty - Time complexity: ? - Space complexity: ? + Time complexity: constant ? + Space complexity: constant ? """ - pass - + if len(self.store) == 0: + return True def heap_up(self, index): """ This helper method takes an index and moves the corresponding element up the heap, if it is less than it's parent node until the Heap property is reestablished. - + This could be **very** helpful for the add method. - Time complexity: ? - Space complexity: ? + Time complexity: O(log n) ? + Space complexity: O(log n) ? """ - pass + if index == 0: + return + + parent = (index - 1) // 2 + store = self.store + if store[parent].key > store[index].key: + self.swap(parent, index) + self.heap_up(parent) def heap_down(self, index): """ This helper method takes an index and @@ -68,9 +88,23 @@ def heap_down(self, index): larger than either of its children and continues until the heap property is reestablished. """ - pass + lchild = index * 2 + 1 + rchild = index * 2 + 2 + store = self.store + + if lchild < len(self.store): + if rchild < len(self.store): + if store[lchild].key < store[rchild].key: + smaller = lchild + else: + smaller = rchild + else: + smaller = lchild + + if store[index].key > store[smaller].key: + self.swap(index, smaller) + self.heap_down(smaller) - def swap(self, index_1, index_2): """ Swaps two elements in self.store at index_1 and index_2