diff --git a/src/data-structures/heap.js b/src/data-structures/heap.js
index cb936575..e329f831 100644
--- a/src/data-structures/heap.js
+++ b/src/data-structures/heap.js
@@ -1,34 +1,22 @@
/**
- * A binary heap is a complete binary tree which
- * satisfies the heap ordering property.
+ * A binary heap is a complete binary tree that satisfies the heap ordering property.
+ * This implementation supports both minimum and maximum heaps, depending on the
+ * comparison function provided. If no comparison function is provided, it defaults to
+ * a minimum heap.
*
* @example
* var Heap = require('path-to-algorithms/src/data-structures/heap').Heap;
*
+ * // Example for a max heap using birthyear for comparison:
* var heap = new Heap(function(a, b) {
* return a.birthyear - b.birthyear;
* });
*
- * heap.add({
- * name: 'John',
- * birthyear: 1981
- * });
- * heap.add({
- * name: 'Pavlo',
- * birthyear: 2000
- * });
- * heap.add({
- * name: 'Garry',
- * birthyear: 1989
- * });
- * heap.add({
- * name: 'Derek',
- * birthyear: 1990
- * });
- * heap.add({
- * name: 'Ivan',
- * birthyear: 1966
- * });
+ * heap.add({ name: 'John', birthyear: 1981 });
+ * heap.add({ name: 'Pavlo', birthyear: 2000 });
+ * heap.add({ name: 'Garry', birthyear: 1989 });
+ * heap.add({ name: 'Derek', birthyear: 1990 });
+ * heap.add({ name: 'Ivan', birthyear: 1966 });
*
* console.log(heap.extract()); // { name: 'Pavlo', birthyear: 2000 }
* console.log(heap.extract()); // { name: 'Derek', birthyear: 1990 }
@@ -39,96 +27,111 @@
* @module data-structures/heap
*/
(function (exports) {
-
- 'use strict';
+ "use strict";
/**
- * Minimum heap constructor.
+ * Heap constructor.
+ * The heap can be either a min-heap or max-heap, determined by the comparison function.
+ * By default, it behaves as a min-heap if no comparison function is provided.
*
* @public
* @constructor
- * @param {Function} cmp Function used for comparison between the elements.
+ * @param {Function} cmp A function used for comparing elements (optional).
+ * It should return a positive number if a > b,
+ * a negative number if a < b, and 0 if they are equal.
*/
exports.Heap = function (cmp) {
this._heap = [];
- if (typeof cmp === 'function') {
- this._cmp = cmp;
- } else {
- this._cmp = function (a, b) {
- return a - b;
- };
- }
+ // If comparison function is provided, use it; otherwise, use default for min-heap.
+ this._cmp =
+ typeof cmp === "function"
+ ? cmp
+ : function (a, b) {
+ return a - b;
+ };
};
/**
- * Exchange indexes with start index given as argument
- * to turn the tree into a valid heap. On a single call
- * this method maintains only a single "branch" of the heap.
+ * Heapifies the subtree rooted at the given index, maintaining the heap property.
+ * This method assumes that the subtrees are already valid heaps and fixes the
+ * heap rooted at the provided index.
*
* Time complexity: O(log N).
*
* @private
- * @param {Number} index The parent.
+ * @param {Number} index Index of the node to heapify.
*/
exports.Heap.prototype._heapify = function (index) {
- var extr = index;
- var left = 2 * index + 1;
- var right = 2 * index + 2;
+ var largest = index;
+ var left = 2 * index + 1; // Left child index
+ var right = 2 * index + 2; // Right child index
var temp;
- if (left < this._heap.length &&
- this._cmp(this._heap[left], this._heap[index]) > 0) {
- extr = left;
+ // Compare the left child with the current node (index).
+ if (
+ left < this._heap.length &&
+ this._cmp(this._heap[left], this._heap[index]) > 0
+ ) {
+ largest = left;
}
- if (right < this._heap.length &&
- this._cmp(this._heap[right], this._heap[index]) > 0 &&
- this._cmp(this._heap[right], this._heap[left]) > 0) {
- extr = right;
+ // Compare the right child with the current largest node.
+ if (
+ right < this._heap.length &&
+ this._cmp(this._heap[right], this._heap[largest]) > 0
+ ) {
+ largest = right;
}
- if (index !== extr) {
+ // If the largest node is not the current index, swap and heapify.
+ if (largest !== index) {
temp = this._heap[index];
- this._heap[index] = this._heap[extr];
- this._heap[extr] = temp;
- this._heapify(extr);
+ this._heap[index] = this._heap[largest];
+ this._heap[largest] = temp;
+ // Recursively heapify the affected subtree.
+ this._heapify(largest);
}
};
/**
- * Changes the key.
- * Complexity: O(log N).
+ * Changes the key/value of the element at the given index and repositions it
+ * to maintain the heap property.
+ *
+ * Time complexity: O(log N).
*
* @public
- * @param {Number} index Index of the value which should be changed.
- * @param {Number|Object} value New value according to the index.
- * @return {Number} New position of the element.
+ * @param {Number} index Index of the element to change.
+ * @param {Number|Object} value The new value for the element.
+ * @return {Number} The new position of the element.
*/
exports.Heap.prototype.changeKey = function (index, value) {
this._heap[index] = value;
var elem = this._heap[index];
- var parent = Math.floor(index / 2);
+ var parent = Math.floor((index - 1) / 2); // Parent index (use (index-1)/2 for zero-based index).
var temp;
- if (elem !== undefined) {
- while (parent >= 0 && this._cmp(elem, this._heap[parent]) > 0) {
- temp = this._heap[parent];
- this._heap[parent] = elem;
- this._heap[index] = temp;
- index = parent;
- parent = Math.floor(parent / 2);
- }
- this._heapify(index);
+
+ // Move the element up the tree if it's greater than its parent.
+ while (index > 0 && this._cmp(elem, this._heap[parent]) > 0) {
+ temp = this._heap[parent];
+ this._heap[parent] = elem;
+ this._heap[index] = temp;
+ index = parent;
+ parent = Math.floor((parent - 1) / 2);
}
- return parent;
+
+ // Ensure the heap is valid after key change.
+ this._heapify(index);
+ return index;
};
/**
- * Updates a given node. This operation is useful
- * in algorithms like Dijkstra, A* where we need
- * to decrease/increase value of the given node.
+ * Updates a specific node by repositioning it in the heap to maintain the heap property.
+ * This is useful in algorithms where node values need to be updated, such as Dijkstra's or A*.
+ *
+ * Time complexity: O(log N).
*
* @public
- * @param {Number|Object} node Node which should be updated.
+ * @param {Number|Object} node The node to be updated.
*/
exports.Heap.prototype.update = function (node) {
var idx = this._heap.indexOf(node);
@@ -138,58 +141,74 @@
};
/**
- * Adds new element to the heap.
- * Complexity: O(log N).
+ * Adds a new element to the heap, maintaining the heap property.
+ *
+ * Time complexity: O(log N).
*
* @public
- * @param {Number|Object} value Value which will be inserted.
- * @return {Number} Index of the inserted value.
+ * @param {Number|Object} value The value to be added to the heap.
+ * @return {Number} The index of the inserted value.
*/
exports.Heap.prototype.add = function (value) {
+ // Insert the value at the end of the array and then move it to the correct position.
this._heap.push(value);
return this.changeKey(this._heap.length - 1, value);
};
/**
- * Returns current value which is on the top of the heap.
- * Complexity: O(1).
+ * Retrieves, but does not remove, the element at the top of the heap (the extremum).
+ *
+ * Time complexity: O(1).
*
* @public
- * @return {Number|Object} Current top value.
+ * @return {Number|Object} The current top value of the heap.
*/
exports.Heap.prototype.top = function () {
return this._heap[0];
};
/**
- * Removes and returns the current extremum value
- * which is on the top of the heap.
- * Complexity: O(log N).
+ * Removes and returns the top (extremum) element from the heap.
+ * After removal, the heap property is restored.
+ *
+ * Time complexity: O(log N).
*
* @public
- * @returns {Number|Object} The extremum value.
+ * @return {Number|Object} The extremum value removed from the heap.
+ * @throws Will throw an error if the heap is empty.
*/
exports.Heap.prototype.extract = function () {
- if (!this._heap.length) {
- throw 'The heap is already empty!';
+ if (this._heap.length === 0) {
+ throw new Error("The heap is already empty!");
+ }
+
+ // Swap the top element with the last one, remove the last, and heapify the top.
+ var extr = this._heap[0];
+ var last = this._heap.pop();
+ if (this._heap.length > 0) {
+ this._heap[0] = last;
+ this._heapify(0);
}
- var extr = this._heap.shift();
- this._heapify(0);
return extr;
};
+ /**
+ * Returns the entire collection of the heap's elements.
+ *
+ * @public
+ * @return {Array} An array representing the heap's internal collection.
+ */
exports.Heap.prototype.getCollection = function () {
return this._heap;
};
/**
- * Checks or heap is empty.
+ * Checks if the heap is empty.
*
* @public
- * @returns {Boolean} Returns true if heap is empty.
+ * @return {Boolean} True if the heap is empty, otherwise false.
*/
exports.Heap.prototype.isEmpty = function () {
- return !this._heap.length;
+ return this._heap.length === 0;
};
-
-})(typeof window === 'undefined' ? module.exports : window);
+})(typeof window === "undefined" ? module.exports : window);