diff --git a/heaps/heap_sort.py b/heaps/heap_sort.py index 3b834a5..672544a 100644 --- a/heaps/heap_sort.py +++ b/heaps/heap_sort.py @@ -1,8 +1,15 @@ - +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(nlogn) + Space Complexity: O(n) """ - pass \ No newline at end of file + heap = MinHeap() + sorted = [] + for item in list: + heap.add(item) + for i in range(len(list)): + sorted.append(heap.remove()) + return sorted + \ No newline at end of file diff --git a/heaps/min_heap.py b/heaps/min_heap.py index f6fe4e0..1231173 100644 --- a/heaps/min_heap.py +++ b/heaps/min_heap.py @@ -1,3 +1,5 @@ +import operator + class HeapNode: def __init__(self, key, value): @@ -19,18 +21,28 @@ def __init__(self): 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(logn) + Space complexity: O(logn) because of the call stack """ - pass + self.store.append(HeapNode(key, value or key)) + 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(logn) + Space complexity: O(logn) because of the call stack """ - pass + if self.empty(): + return None + if len(self.store) == 1: + return self.store.pop().value + minimum = self.store[0] + self.store[0] = self.store.pop() + self.heap_down(0) + + return minimum.value + @@ -44,10 +56,10 @@ def __str__(self): def empty(self): """ This method returns true if the heap is empty - Time complexity: ? - Space complexity: ? + Time complexity: O(1) + Space complexity: O(1) """ - pass + return len(self.store) == 0 def heap_up(self, index): @@ -57,10 +69,16 @@ def heap_up(self, index): property is reestablished. This could be **very** helpful for the add method. - Time complexity: ? - Space complexity: ? + Time complexity: O(logn) + Space complexity: O(logn) because of the call stack """ - pass + if index == 0: + return + parent = (index-1)//2 + if self.store[parent].key > self.store[index].key: + self.swap(parent, index) + self.heap_up(parent) + def heap_down(self, index): """ This helper method takes an index and @@ -68,7 +86,29 @@ def heap_down(self, index): larger than either of its children and continues until the heap property is reestablished. """ - pass + def get_valid_index_or_none(index): + if index < len(self.store): + return index + else: + return None + + def get_key_or_none(index): + if not index: + return None + return self.store[index].key + + left_index = get_valid_index_or_none(index * 2 + 1) + right_index = get_valid_index_or_none(index * 2 + 2) + + left_key = get_key_or_none(left_index) + right_key = get_key_or_none(right_index) + + index_to_swap = min((node for node in [(left_index, left_key), (right_index, right_key)] if node[1] is not None ), key=operator.itemgetter(1), default=None) + + if index_to_swap and self.store[index].key > index_to_swap[1]: + self.swap(index, index_to_swap[0]) + self.heap_down(index_to_swap[0]) + def swap(self, index_1, index_2): diff --git a/tests/test_min_heap.py b/tests/test_min_heap.py index 5ec272c..7d973e5 100644 --- a/tests/test_min_heap.py +++ b/tests/test_min_heap.py @@ -1,3 +1,4 @@ +import logging import pytest from heaps.min_heap import MinHeap @@ -69,12 +70,15 @@ def test_it_can_remove_nodes_in_proper_order(heap): heap.add(0, "Donuts") heap.add(16, "Cookies") + print(str(heap)) # Act returned_items = ["Donuts", "Pizza", "Pasta", "Soup", "Cookies", "Cake"] + for item in returned_items: assert heap.remove() == item + print(str(heap)) def test_removing_a_node_from_an_empty_heap_is_none(heap): assert heap.remove() == None