From 0264d864850a8e3204145c3df114f9f36d1f0618 Mon Sep 17 00:00:00 2001 From: eyas-ranjous Date: Sat, 11 Oct 2025 16:42:22 -0700 Subject: [PATCH 1/2] fix heap on initialization --- src/heap.js | 10 +++- src/maxHeap.js | 139 ++++--------------------------------------- src/minHeap.js | 139 ++++--------------------------------------- test/heap.test.js | 18 ++++++ test/maxHeap.test.js | 18 ++++++ test/minHeap.test.js | 28 +++++++++ 6 files changed, 95 insertions(+), 257 deletions(-) diff --git a/src/heap.js b/src/heap.js index 4c4d52d..3f279b3 100644 --- a/src/heap.js +++ b/src/heap.js @@ -7,16 +7,20 @@ class Heap { /** * @param {function} compare - * @param {array} [_values] + * @param {array} [values] * @param {number|string|object} [_leaf] */ - constructor(compare, _values, _leaf) { + constructor(compare, values, _leaf) { if (typeof compare !== 'function') { throw new Error('Heap constructor expects a compare function'); } this._compare = compare; - this._nodes = Array.isArray(_values) ? _values : []; + this._nodes = Array.isArray(values) ? values.slice() : []; this._leaf = _leaf || null; + + if (this._nodes.length > 0) { + this.fix(); + } } /** diff --git a/src/maxHeap.js b/src/maxHeap.js index 1b624f5..52fb7e8 100644 --- a/src/maxHeap.js +++ b/src/maxHeap.js @@ -15,14 +15,14 @@ const getMaxCompare = (getCompareValue) => (a, b) => { * @class MaxHeap * @extends Heap */ -class MaxHeap { +class MaxHeap extends Heap { /** * @param {function} [getCompareValue] - * @param {Heap} [_heap] + * @param {array} [values] */ - constructor(getCompareValue, _heap) { + constructor(getCompareValue, values) { + super(getMaxCompare(getCompareValue), values); this._getCompareValue = getCompareValue; - this._heap = _heap || new Heap(getMaxCompare(getCompareValue)); } /** @@ -32,124 +32,28 @@ class MaxHeap { * @returns {MaxHeap} */ insert(value) { - return this._heap.insert(value); + super.insert(value); + return this; } /** * Inserts a new value into the heap * @public * @param {number|string|object} value - * @returns {Heap} + * @returns {MaxHeap} */ push(value) { return this.insert(value); } - /** - * Removes and returns the root node in the heap - * @public - * @returns {number|string|object} - */ - extractRoot() { - return this._heap.extractRoot(); - } - - /** - * Removes and returns the root node in the heap - * @public - * @returns {number|string|object} - */ - pop() { - return this.extractRoot(); - } - - /** - * Applies heap sort and return the values sorted by priority - * @public - * @returns {array} - */ - sort() { - return this._heap.sort(); - } - - /** - * Converts the heap to a cloned array without sorting. - * @public - * @returns {Array} - */ - toArray() { - return Array.from(this._heap._nodes); - } - /** * Fixes node positions in the heap * @public * @returns {MaxHeap} */ fix() { - return this._heap.fix(); - } - - /** - * Verifies that all heap nodes are in the right position - * @public - * @returns {boolean} - */ - isValid() { - return this._heap.isValid(); - } - - /** - * Returns the root node in the heap - * @public - * @returns {number|string|object} - */ - root() { - return this._heap.root(); - } - - /** - * Returns the root node in the heap - * @public - * @returns {number|string|object} - */ - top() { - return this.root(); - } - - /** - * Returns a leaf node in the heap - * @public - * @returns {number|string|object} - */ - leaf() { - return this._heap.leaf(); - } - - /** - * Returns the number of nodes in the heap - * @public - * @returns {number} - */ - size() { - return this._heap.size(); - } - - /** - * Checks if the heap is empty - * @public - * @returns {boolean} - */ - isEmpty() { - return this._heap.isEmpty(); - } - - /** - * Clears the heap - * @public - */ - clear() { - this._heap.clear(); + super.fix(); + return this; } /** @@ -158,24 +62,7 @@ class MaxHeap { * @returns {MaxHeap} */ clone() { - return new MaxHeap(this._getCompareValue, this._heap.clone()); - } - - /** - * Implements an iterable on the heap - * @public - */ - [Symbol.iterator]() { - let size = this.size(); - return { - next: () => { - size -= 1; - return { - value: this.pop(), - done: size === -1 - }; - } - }; + return new MaxHeap(this._getCompareValue, this._nodes.slice()); } /** @@ -190,8 +77,7 @@ class MaxHeap { if (!Array.isArray(values)) { throw new Error('MaxHeap.heapify expects an array'); } - const heap = new Heap(getMaxCompare(getCompareValue), values); - return new MaxHeap(getCompareValue, heap).fix(); + return new MaxHeap(getCompareValue, values); } /** @@ -203,8 +89,7 @@ class MaxHeap { * @returns {boolean} */ static isHeapified(values, getCompareValue) { - const heap = new Heap(getMaxCompare(getCompareValue), values); - return new MaxHeap(getCompareValue, heap).isValid(); + return new MaxHeap(getCompareValue, values).isValid(); } } diff --git a/src/minHeap.js b/src/minHeap.js index 1b4f443..1686cc1 100644 --- a/src/minHeap.js +++ b/src/minHeap.js @@ -15,23 +15,14 @@ const getMinCompare = (getCompareValue) => (a, b) => { * @class MinHeap * @extends Heap */ -class MinHeap { +class MinHeap extends Heap { /** * @param {function} [getCompareValue] - * @param {Heap} [_heap] + * @param {array} [values] */ - constructor(getCompareValue, _heap) { + constructor(getCompareValue, values) { + super(getMinCompare(getCompareValue), values); this._getCompareValue = getCompareValue; - this._heap = _heap || new Heap(getMinCompare(getCompareValue)); - } - - /** - * Converts the heap to a cloned array without sorting. - * @public - * @returns {Array} - */ - toArray() { - return Array.from(this._heap._nodes); } /** @@ -41,115 +32,28 @@ class MinHeap { * @returns {MinHeap} */ insert(value) { - return this._heap.insert(value); + super.insert(value); + return this; } /** * Inserts a new value into the heap * @public * @param {number|string|object} value - * @returns {Heap} + * @returns {MinHeap} */ push(value) { return this.insert(value); } - /** - * Removes and returns the root node in the heap - * @public - * @returns {number|string|object} - */ - extractRoot() { - return this._heap.extractRoot(); - } - - /** - * Removes and returns the root node in the heap - * @public - * @returns {number|string|object} - */ - pop() { - return this.extractRoot(); - } - - /** - * Applies heap sort and return the values sorted by priority - * @public - * @returns {array} - */ - sort() { - return this._heap.sort(); - } - /** * Fixes node positions in the heap * @public * @returns {MinHeap} */ fix() { - return this._heap.fix(); - } - - /** - * Verifies that all heap nodes are in the right position - * @public - * @returns {boolean} - */ - isValid() { - return this._heap.isValid(); - } - - /** - * Returns the root node in the heap - * @public - * @returns {number|string|object} - */ - root() { - return this._heap.root(); - } - - /** - * Returns the root node in the heap - * @public - * @returns {number|string|object} - */ - top() { - return this.root(); - } - - /** - * Returns a leaf node in the heap - * @public - * @returns {number|string|object} - */ - leaf() { - return this._heap.leaf(); - } - - /** - * Returns the number of nodes in the heap - * @public - * @returns {number} - */ - size() { - return this._heap.size(); - } - - /** - * Checks if the heap is empty - * @public - * @returns {boolean} - */ - isEmpty() { - return this._heap.isEmpty(); - } - - /** - * Clears the heap - * @public - */ - clear() { - this._heap.clear(); + super.fix(); + return this; } /** @@ -158,24 +62,7 @@ class MinHeap { * @returns {MinHeap} */ clone() { - return new MinHeap(this._getCompareValue, this._heap.clone()); - } - - /** - * Implements an iterable on the heap - * @public - */ - [Symbol.iterator]() { - let size = this.size(); - return { - next: () => { - size -= 1; - return { - value: this.pop(), - done: size === -1 - }; - } - }; + return new MinHeap(this._getCompareValue, this._nodes.slice()); } /** @@ -190,8 +77,7 @@ class MinHeap { if (!Array.isArray(values)) { throw new Error('MinHeap.heapify expects an array'); } - const heap = new Heap(getMinCompare(getCompareValue), values); - return new MinHeap(getCompareValue, heap).fix(); + return new MinHeap(getCompareValue, values); } /** @@ -203,8 +89,7 @@ class MinHeap { * @returns {boolean} */ static isHeapified(values, getCompareValue) { - const heap = new Heap(getMinCompare(getCompareValue), values); - return new MinHeap(getCompareValue, heap).isValid(); + return new MinHeap(getCompareValue, values).isValid(); } } diff --git a/test/heap.test.js b/test/heap.test.js index 76a5b12..6749325 100644 --- a/test/heap.test.js +++ b/test/heap.test.js @@ -195,4 +195,22 @@ describe('Heap', () => { expect(h1.toArray().sort((a, b) => a - b)).to.eql(testArr); }); }); + + describe('constructor with initial values', () => { + it('should properly heapify initial values and maintain heap property after insertions', () => { + const heap = new Heap((a, b) => a - b, [3, 1, 4]); + expect(heap.isValid()).to.equal(true); + + heap.insert(2); + expect(heap.toArray()).to.eql([1, 2, 4, 3]); + expect(heap.isValid()).to.equal(true); + }); + + it('should handle insertion of smallest element correctly', () => { + const heap1 = new Heap((a, b) => a - b, [3, 1, 4]); + heap1.insert(0); + expect(heap1.toArray()).to.eql([0, 1, 4, 3]); + expect(heap1.isValid()).to.equal(true); + }); + }); }); diff --git a/test/maxHeap.test.js b/test/maxHeap.test.js index 2607bc0..4d917c0 100644 --- a/test/maxHeap.test.js +++ b/test/maxHeap.test.js @@ -153,4 +153,22 @@ describe('MaxHeap', () => { expect(h1.toArray().sort((a, b) => -a + b)).to.eql(testArr); }); }); + + describe('constructor with initial values', () => { + it('should properly heapify initial values and maintain heap property after insertions', () => { + const heap = new MaxHeap(null, [3, 1, 4]); + expect(heap.isValid()).to.equal(true); + + heap.insert(2); + expect(heap.toArray()).to.eql([4, 2, 3, 1]); + expect(heap.isValid()).to.equal(true); + }); + + it('should handle insertion of largest element correctly', () => { + const heap1 = new MaxHeap(null, [3, 1, 4]); + heap1.insert(5); + expect(heap1.toArray()).to.eql([5, 4, 3, 1]); + expect(heap1.isValid()).to.equal(true); + }); + }); }); diff --git a/test/minHeap.test.js b/test/minHeap.test.js index fc9c07a..93a1f87 100644 --- a/test/minHeap.test.js +++ b/test/minHeap.test.js @@ -138,6 +138,16 @@ describe('MinHeap', () => { } expect(res).to.eql(testArr); }); + + it('iterates correctly with duplicates', () => { + const heap2 = new MinHeap(); + [3, 1, 4, 1, 5].forEach((n) => heap2.insert(n)); + const result = []; + for (const num of heap2) { + result.push(num); + } + expect(result).to.eql([1, 1, 3, 4, 5]); + }); }); describe('toArray', () => { @@ -147,4 +157,22 @@ describe('MinHeap', () => { expect(h1.toArray().sort((a, b) => a - b)).to.eql(testArr); }); }); + + describe('constructor with initial values', () => { + it('should properly heapify initial values and maintain heap property after insertions', () => { + const heap = new MinHeap(null, [3, 1, 4]); + expect(heap.isValid()).to.equal(true); + + heap.insert(2); + expect(heap.toArray()).to.eql([1, 2, 4, 3]); + expect(heap.isValid()).to.equal(true); + }); + + it('should handle insertion of smallest element correctly', () => { + const heap1 = new MinHeap(null, [3, 1, 4]); + heap1.insert(0); + expect(heap1.toArray()).to.eql([0, 1, 4, 3]); + expect(heap1.isValid()).to.equal(true); + }); + }); }); From d61ca6d3f98544c2e5340f3b26a756a3c350a4d9 Mon Sep 17 00:00:00 2001 From: eyas-ranjous Date: Sat, 11 Oct 2025 16:43:44 -0700 Subject: [PATCH 2/2] remove --- src/heap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heap.js b/src/heap.js index 3f279b3..c8326d1 100644 --- a/src/heap.js +++ b/src/heap.js @@ -15,7 +15,7 @@ class Heap { throw new Error('Heap constructor expects a compare function'); } this._compare = compare; - this._nodes = Array.isArray(values) ? values.slice() : []; + this._nodes = Array.isArray(values) ? values : []; this._leaf = _leaf || null; if (this._nodes.length > 0) {