From 9c88bfd61782d80296698ab342d6d1837fd10ecd Mon Sep 17 00:00:00 2001 From: Jasmine Date: Wed, 28 Apr 2021 22:04:30 -0700 Subject: [PATCH] implemented min_heap & heapsort --- lib/heap_sort.rb | 59 ++++++++++++++++++++++++++++++++++++++++--- lib/min_heap.rb | 55 ++++++++++++++++++++++++++++++---------- test/heapsort_test.rb | 2 +- 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/lib/heap_sort.rb b/lib/heap_sort.rb index c8a32a4..0c68407 100644 --- a/lib/heap_sort.rb +++ b/lib/heap_sort.rb @@ -1,8 +1,59 @@ # This method uses a heap to sort an array. -# Time Complexity: ? -# Space Complexity: ? -def heap_sort(list) - raise NotImplementedError, "Method not implemented yet..." +# Time Complexity: O(n * log(n)) where n is the number of elements. +# Space Complexity: O(log(n)) worsecase because of recursion inside of heapify? +# list = [5, 27, 3, 16, -50] +def heapsort(list) + return list if list.empty? || list.length == 1 + + # i = the parent of the last element + i = (list.size - 1) / 2 + # initial heapify of list + while i >= 0 + heapify(list, i, list.length) + i -= 1 + end + + # list = [-50, 5, 3, 16, 27 ] + i = 0 + j = list.length - 1 + while j >= 0 + swap(i, j, list) + j -= 1 + heapify(list, 0, j) + end + +return list +end + +def swap(index1, index2, list) + temp = list[index1] + list[index1] = list[index2] + list[index2] = temp +end + +def heapify(list, index, size) + # index here will be the "root" node + largest = index + left = 2 * index + 1 + right = 2 * index + 2 + + # check if left child is greater than parent + if left < size && list[left] > list[largest] + largest = left + end + + # also check if right child is greater than parent + if right < size && list[right] > list[largest] + largest = right + end + + # if the largest no longer equals it's original value + if largest != index + # swap the root and the found largest value + swap(largest, index, list) + # make sure the order is still maintained for the children of that new index + heapify(list, largest, size) + end end \ No newline at end of file diff --git a/lib/min_heap.rb b/lib/min_heap.rb index 6eaa630..b25a36f 100644 --- a/lib/min_heap.rb +++ b/lib/min_heap.rb @@ -14,18 +14,27 @@ def initialize end # This method adds a HeapNode instance to the heap - # Time Complexity: ? - # Space Complexity: ? + # Time Complexity: O(log(n)) + # Space Complexity: O(log(n) due to the stack call in heap_up, could be O(1) using a loop def add(key, value = key) - raise NotImplementedError, "Method not implemented yet..." + node = HeapNode.new(key, value) + @store.push(node) + heap_up(@store.length - 1) end # This method removes and returns an element from the heap # maintaining the heap structure - # Time Complexity: ? - # Space Complexity: ? + # Time Complexity: O(log(n)) - where n is the number of elements and log(n) reps the levels + # Space Complexity: O(log(n) due to the stack call in heap_down, could be O(1) using a loop def remove() - raise NotImplementedError, "Method not implemented yet..." + if @store.length == 0 + raise "the heap is empty" + end + + swap(0, @store.length - 1) + removed = @store.pop + heap_down(0) + return removed.value end @@ -44,10 +53,10 @@ def to_s end # This method returns true if the heap is empty - # Time complexity: ? - # Space complexity: ? + # Time complexity: O(1) + # Space complexity: O(1) def empty? - raise NotImplementedError, "Method not implemented yet..." + return @store.length == 0 end private @@ -55,17 +64,37 @@ def empty? # This helper method takes an index and # moves it up the heap, if it is less than it's parent node. # It could be **very** helpful for the add method. - # Time complexity: ? - # Space complexity: ? + # Time complexity: O(log(n)) - n for number of elements. log(n) represents the number of levels. + # Space complexity: O(log(n)) - the stack for the resursive calls could be as tall as the number of levels. def heap_up(index) - + return if index == 0 + parent_idx = (index - 1) / 2 + if @store[parent_idx].key > @store[index].key + swap(parent_idx, index) + heap_up(parent_idx) + end end # This helper method takes an index and # moves it up the heap if it's smaller # than it's parent node. def heap_down(index) - raise NotImplementedError, "Method not implemented yet..." + left = 2 * index + 1 + right = 2 * index + 2 + if @store[left] && @store[right] # if both left and right are not nil + child_idx = @store[left].key > @store[right].key ? right : left + elsif @store[left] # there's no case where the left would be null and the right have a value + child_idx = left + else # if they're both null stop the function and return. + return + end + + if @store[child_idx].key < @store[index].key + swap(child_idx, index) + heap_down(child_idx) + end + + end # If you want a swap method... you're welcome diff --git a/test/heapsort_test.rb b/test/heapsort_test.rb index 34402ac..7ce79b7 100644 --- a/test/heapsort_test.rb +++ b/test/heapsort_test.rb @@ -1,6 +1,6 @@ require_relative "test_helper" -xdescribe "heapsort" do +describe "heapsort" do it "sorts an empty array" do # Arrange list = []