class MaxHeap { constructor(arr = []){ this.size = 0 this.values = this._heapify(arr) } insert(value){ // If no value, do nothing if (value === undefined) return // Insert the value, and increment the size of the heap this.values.push(value) this.size++ // Check to see if there is not more than 1 item in the heap // If there is only 1 item, there is no need to bubble up if (this.size > 1) this._bubbleUp() return this.values } extract(){ if (this.size === 0) return const lastIndex = this.size - 1 this.size-- this._swap(0, lastIndex) const extractValue = this.values.pop() if (this.size > 1) this._trickleDown() return extractValue } // Helper function using object destructuring to swap the elements at two indices _swap(index1, index2){ [this.values[index1], this.values[index2]] = [this.values[index2], this.values[index1]] } _heapify(arr){ if (this.size > 0) return // Optional: Prevent overriding existing heap values this.size = arr.length /** * To prevent mutating current array, replace line 18 with * this.values = [...arr] */ this.values = arr const nodeCount = this.size - 1 // Finds the last node of the tree that has children let cIdx = Math.floor((nodeCount - 2)/2) /** For each node up through the root, * call trickleDown */ for (let i = cIdx; i >= 0; i--){ this._trickleDown(i) } return this.values } _bubbleUp(){ // Grab the most recently added value and its parent let currentIndex = this.size - 1 let parentIndex = Math.floor( (currentIndex - 1) / 2 ) // Swap the new node with its parent until the new node either // becomes the root, or is no longer greater than its parent while (parentIndex >= 0 && this.values[currentIndex] > this.values[parentIndex]){ this._swap(currentIndex, parentIndex) currentIndex = parentIndex parentIndex = Math.floor((currentIndex - 1) / 2 ) } } _trickleDown(start = 0, stop = this.size){ let currentIndex = start /** * These will be the indexes corresponding to the left and right * child of the node at currentIndex * swapIdx will be which of the children the currentIndex will * actually switch with, if any */ let leftIdx, rightIdx, swapIdx while (true) { leftIdx = 2 * currentIndex + 1 rightIdx = 2 * currentIndex + 2 swapIdx = null /** * If there is a valid left child and it is greater than the current value, * prepare to swap it */ if ( leftIdx < stop && this.values[currentIndex] < this.values[leftIdx] ) { swapIdx = leftIdx } /** * If there is a valid right child and it is greater than the current value, * prepare to swap it if we haven't already prepared to swap with left child. * If we have prepared to swap with left child, we should only choose to swapIdx * with the right child instead if it is greater than the left child, meaning * it better fits the heap rule */ if ( rightIdx < stop && ((swapIdx === null && this.values[currentIndex] < this.values[rightIdx]) || (swapIdx !== null && this.values[rightIdx] > this.values[leftIdx])) ) { swapIdx = rightIdx } if (swapIdx === null) break // If no possibel swap was ID'd, we're done // Swap the parent with the identified child, update the currentIndex, and repeat this._swap(currentIndex, swapIdx) currentIndex = swapIdx } } static heapSort(arr){ const heap = new MaxHeap(arr) for (let i = arr.length - 1; i > 0; i--){ heap._swap(0,i) heap._trickleDown(0, i) } return heap.values } }