diff --git a/lib/heapsort.js b/lib/heapsort.js index 69d5af2..f4368b2 100644 --- a/lib/heapsort.js +++ b/lib/heapsort.js @@ -1,8 +1,23 @@ +const { MinHeap } = require('../lib/minheap'); // This method uses a heap to sort an array. -// Time Complexity: ? -// Space Complexity: ? +// Time Complexity: O(n log n) - iterating over list (n) while running .add()/.remove() (both log n) +// Space Complexity: O(n), where n is length of list + function heapsort(list) { - throw new Error('Method not implemented yet...'); -}; + if (list.length <= 1) return list; + + const heap = new MinHeap(); + + list.forEach(item => { + heap.add(item) + }) + + for (let i = 0; i < list.length; i++) { + // rewriting the original list ♻️ + list[i] = heap.remove(); + } + + return list; +} module.exports = heapsort; diff --git a/lib/minheap.js b/lib/minheap.js index 4efceaf..c981cb4 100644 --- a/lib/minheap.js +++ b/lib/minheap.js @@ -11,18 +11,27 @@ class MinHeap { } // This method adds a HeapNode instance to the heap - // Time Complexity: ? - // Space Complexity: ? + // Time Complexity: O(log n), if we include the heapUp helper function + // Space Complexity: O(log n), because of the recursive heapUp stack add(key, value = key) { - throw new Error("Method not implemented yet..."); + this.store.push(new HeapNode(key, value)); + if (this.store.length === 1) { + return; + } else { + this.heapUp(this.store.length - 1) + } } // 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) remove() { - throw new Error("Method not implemented yet..."); + if (this.isEmpty()) return; + this.swap(0, this.store.length - 1) + const removedNode = this.store.pop(); + this.heapDown(0); + return removedNode.value; } @@ -38,26 +47,57 @@ class MinHeap { } // This method returns true if the heap is empty - // Time complexity: ? - // Space complexity: ? + // Time complexity: O(1) of course! + // Space complexity: O(1). never felt more confident with space complexity. isEmpty() { - throw new Error("Method not implemented yet..."); + return this.store.length === 0 } // 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) + // Space complexity: O(log n) heapUp(index) { - throw new Error("Method not implemented yet..."); + + const parent = Math.floor((index - 1) / 2); + if (this.store[parent].key > this.store[index].key) { + this.swap(parent, index); + // heap up until we hit the root + if (parent > 0) this.heapUp(parent); + } + } // This helper method takes an index and // moves it up the heap if it's smaller // than it's parent node. + // time complexity: O(log n) + // space complexity: O(log n), because of the recursive stack heapDown(index) { - throw new Error("Method not implemented yet..."); + + // to shorten code lines instead of writing out 'this.store' every time + const s = this.store; + + if (index >= s.length) return; + + let leftChild = index * 2 + 1 + let rightChild = index * 2 + 2 + + // return if there is no left child node + if (s[leftChild] === undefined) { + return; + } + + // find smaller child node between left & right + let minChild = rightChild; + if (s[rightChild] === undefined || s[leftChild].key <= s[rightChild].key) minChild = leftChild + + // swap parent with smaller child + if (s[minChild].key < s[index].key) { + this.swap(minChild, index) + this.heapDown(minChild); + } } // If you want a swap method... you're welcome diff --git a/test/heapsort.test.js b/test/heapsort.test.js index a34282b..9f246e4 100644 --- a/test/heapsort.test.js +++ b/test/heapsort.test.js @@ -1,6 +1,7 @@ const expect = require('chai').expect; +const heapsort = require('../lib/heapsort') -describe.skip("heapsort", function() { +describe("heapsort", function() { it("sorts an empty array", function() { // Arrange const list = [];