diff --git a/CHANGELOG.md b/CHANGELOG.md index a05f659..aeecd83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.1.0] - 2019-12-16 +### Added +`.serialize()` to convert a heap to a list of serialized nodes. + +### Fixed +- improve README. + ## [1.0.1] - 2019-12-16 ### Fixed - Readme & Description. diff --git a/README.md b/README.md index d10cd74..b0878d3 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ import { MinHeap, MaxHeap } from '@datastructures-js/heap'; #### new creates an empty heap. +##### Example ```js const minHeap = new MinHeap(); @@ -38,10 +39,20 @@ const maxHeap = new MaxHeap(); #### .heapify(list) converts an array of objects to a heap. -the function can read a list elements that are **number**, **string**, or a **serialized heap node** like `{ key: 10, value: { someProp: 'someVal' } }`. +##### runtime +O(n) + +##### params +###### list<{number}|{string}|{object}> : {array} +elements can be number, string or serialized heap node objects. + +##### return : {Heap} +*MinHeap* or *MaxHeap* instance. + +##### Example ```js -const list = [ +const numList = [ 50, 80, { key: 30, value: 'something' }, @@ -51,19 +62,35 @@ const list = [ { key: 20, value: { name: 'test' } } ]; -const minHeap = MinHeap.heapify(list); +const strList = [ + 'm', + 'x', + { key: 'f', value: 'something' }, + 'b', + { key: 'z', value: null }, + 'k', + { key: 'c', value: { name: 'test' } } +]; + +const minHeap = MinHeap.heapify(numList); -const maxHeap = MaxHeap.heapify(list); +const maxHeap = MaxHeap.heapify(strList); ``` ### .insert(key, value) insert a node into the heap. -**key** can be a **number** or a **string** +##### runtime +O(log(n)) -**value** can be any **object** type. +##### params +###### key : {number} | {string} +the value that is used to compare nodes in the heap. -a heap node is created as an instance of **NodeHeap**. +###### value : {object} +the value that is associated with a key. + +##### Example ```js const minHeap = new MinHeap(); @@ -78,29 +105,34 @@ minHeap.insert(60, null); minHeap.insert(40); minHeap.insert(20, { name: 'test' }); -maxHeap.insert(50); -maxHeap.insert(80); -maxHeap.insert(30, 'something'); -maxHeap.insert(90); -maxHeap.insert(60, null); -maxHeap.insert(40); -maxHeap.insert(20, { name: 'test' }); +maxHeap.insert('m'); +maxHeap.insert('x'); +maxHeap.insert('f', 'something'); +maxHeap.insert('b'); +maxHeap.insert('z', null); +maxHeap.insert('k'); +maxHeap.insert('c', { name: 'test' }); ``` -### HeapNode -returned with .root() & .extractRoot() functions. It implements the following interface +### .root() +peeks on the root without removing it. + +##### runtime +O(1) + +##### return : {HeapNode} +the root node in the heap. It implements the following interface -#### .getKey() -returns the node's key (number or string) that is used to compare with other nodes. +###### .getKey() +returns the node's key that is used to compare with other nodes. -#### .getValue() +###### .getValue() returns the value that is associated with the key. -#### .serialize() +###### .serialize() returns an object literal of key/value of the node. -### .root() -returns (peeks) the root node without removing it. +##### Example ```js const min = minHeap.root(); @@ -109,13 +141,21 @@ console.log(min.getValue()); // { name: 'test' } console.log(min.serialize()); // { key: 20, value: { name: 'test' } } const max = maxHeap.root(); -console.log(max.getKey()); // 90 -console.log(max.getValue()); // undefined -console.log(max.serialize()); // { key: 90, value: undefined } +console.log(max.getKey()); // 'z' +console.log(max.getValue()); // null +console.log(max.serialize()); // { key: 'z', value: null } ``` ### .extractRoot() -returns and remove the root node in the heap. +removes and returns the root node in the heap. + +##### runtime +O(log(n)) + +##### return : {HeapNode} +the root node in the heap. + +##### Example ```js const min = minHeap.extractRoot(); @@ -125,15 +165,59 @@ console.log(min.serialize()); // { key: 20, value: { name: 'test' } } console.log(minHeap.root().getKey()); // 30 const max = maxHeap.extractRoot(); -console.log(max.getKey()); // 90 -console.log(max.getValue()); // undefined -console.log(max.serialize()); // { key: 20, value: undefined } -console.log(maxHeap.root().getKey()); // 80 +console.log(max.getKey()); // 'z' +console.log(max.getValue()); // null +console.log(max.serialize()); // { key: 'z', value: null } +console.log(maxHeap.root().getKey()); // 'x' +``` + +### .serialize() +converts the heap into a list of serialized nodes. + +##### runtime +O(n) + +##### return : {array\} + +a serialized list of heap nodes + +##### Example + +```js +console.log(minHeap.serialize()); +/* +[ + { key: 30, value: 'something' }, + { key: 60, value: null }, + { key: 40, value: undefined }, + { key: 90, value: undefined }, + { key: 80, value: undefined }, + { key: 50, value: undefined } +] +*/ + +console.log(maxHeap.serialize()); +/* +[ + { key: 'x', value: undefined }, + { key: 'm', value: undefined }, + { key: 'k', value: undefined }, + { key: 'b', value: undefined }, + { key: 'c', value: { name: 'test' } }, + { key: 'f', value: 'something' } +] +*/ ``` ### .size() -returns the number of nodes in the heap. +##### runtime +O(1) + +##### return : {number} +the number of nodes in the heap. + +##### Example ```js console.log(minHeap.size()); // 6 console.log(maxHeap.size()); // 6 @@ -142,6 +226,14 @@ console.log(maxHeap.size()); // 6 ### .clone() creates a shallow copy of a heap by slicing the nodes array and passing it to a new heap instance. +##### runtime +O(n) + +##### return : {Heap} +*MinHeap* or *MaxHeap* instance. + +##### Example + ```js const minHeapClone = minHeap.clone(); minHeapClone.extractRoot(); @@ -151,24 +243,65 @@ console.log(minHeap.root().getKey()); // 30 ``` ### .sort() -implements Heap Sort and sorts a **Max Heap in ascneding order** or a **Min Heap in descending order**. +implements Heap Sort and sorts a *Max Heap in ascneding order* or a *Min Heap in descending order*. + +##### runtime +O(n\*log(n)) + +##### return : {array} +a sorted list by key of the heap nodes. + +*note : calling .sort() directly on a heap will mutate its nodes location. If you want to avoid that, you can sort a shallow copy of the heap.* -calling .sort() directly on a heap will mutate its nodes location. To avoid that, you can sort a shallow copy of the heap. +##### Example ```js -const sortedAsc = maxHeap.clone().sort(); // does not mutate the heap structure -const sortedDesc = minHeap.clone().sort(); // does not mutate the heap structure +console.log(maxHeap.clone().sort()); // does not mutate the heap structure +/* +[ + HeapNode { key: 'b', value: undefined }, + HeapNode { key: 'c', value: { name: 'test' } }, + HeapNode { key: 'f', value: 'something' }, + HeapNode { key: 'k', value: undefined }, + HeapNode { key: 'm', value: undefined }, + HeapNode { key: 'x', value: undefined } +] +*/ +console.log(maxHeap.root()); // HeapNode { key: 'x', value: undefined } + +console.log(minHeap.clone().sort()); // does not mutate the heap structure +/* +[ + HeapNode { key: 90, value: undefined }, + HeapNode { key: 80, value: undefined }, + HeapNode { key: 60, value: null }, + HeapNode { key: 50, value: undefined }, + HeapNode { key: 40, value: undefined }, + HeapNode { key: 30, value: 'something' } +] +*/ +console.log(minHeap.root()); // HeapNode { key: 30, value: 'something' } ``` -If you are using this npm for the purpose of sorting a list of elements using Heap Sort, you can do it like this +If you are using this npm for the purpose of sorting a list of elements using Heap Sort, you can do this: ```js -const sortedAsc = MaxHeap.heapify(unsortedList).sort(); -const sortedDesc = MinHeap.heapify(unsortedList).sort(); +const unsortedList = [3, 7, 2, 10, 4, 9, 8, 5, 1, 6]; + +const ascSorted = MaxHeap.heapify(unsortedList).sort().map(n => n.getKey()); +// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +const descSorted = MinHeap.heapify(unsortedList).sort().map(n => n.getKey()); +// [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] ``` ### .clear() -clears the nodes in the heap +clears the nodes in the heap. + +##### runtime +O(1) + +##### Example ```js minHeap.clear(); diff --git a/package.json b/package.json index 394bc1e..d1b5565 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@datastructures-js/heap", - "version": "1.0.1", + "version": "1.1.0", "description": "Min/Max Heap & Heap Sort implementation in javascript", "main": "index.js", "scripts": { diff --git a/src/heap.js b/src/heap.js index 8ab3352..ec98de8 100644 --- a/src/heap.js +++ b/src/heap.js @@ -191,6 +191,16 @@ class Heap { this.heapifyUp(); } + /** + * returns the root node in the heap + * @public + * @returns {HeapNode} + */ + root() { + if (this.size() === 0) return null; + return this.nodes[0]; + } + /** * removes and returns the root node in the heap * @public @@ -208,22 +218,21 @@ class Heap { } /** - * returns the root node in the heap + * returns the number of nodes in the heap * @public - * @returns {HeapNode} + * @returns {number} */ - root() { - if (this.size() === 0) return null; - return this.nodes[0]; + size() { + return this.nodes.length; } /** - * returns the number of nodes in the heap + * serializes the heap nodes into a list of objects * @public - * @returns {number} + * @returns {array} */ - size() { - return this.nodes.length; + serialize() { + return this.nodes.map((n) => n.serialize()); } /** diff --git a/test/maxHeap.test.js b/test/maxHeap.test.js index 1467c88..3d98f6b 100644 --- a/test/maxHeap.test.js +++ b/test/maxHeap.test.js @@ -46,6 +46,41 @@ describe('MaxHeap unit tests', () => { }); }); + describe('.serialize()', () => { + it('should serialize the heap nodes', () => { + expect(maxHeap.serialize()).to.deep.equal([ + { + key: 90, + value: undefined + }, + { + key: 80, + value: undefined + }, + { + key: 40, + value: undefined + }, + { + key: 50, + value: undefined + }, + { + key: 60, + value: null + }, + { + key: 30, + value: 'something' + }, + { + key: 20, + value: { name: 'test' } + } + ]); + }); + }); + describe('.extractRoot()', () => { it('should extract the root (max key) from the heap', () => { expect(maxHeap.extractRoot().serialize()).to.deep.equal({ diff --git a/test/minHeap.test.js b/test/minHeap.test.js index 612f6b0..8fb5ffa 100644 --- a/test/minHeap.test.js +++ b/test/minHeap.test.js @@ -46,6 +46,41 @@ describe('MinHeap unit tests', () => { }); }); + describe('.serialize()', () => { + it('should serialize the heap nodes', () => { + expect(minHeap.serialize()).to.deep.equal([ + { + key: 20, + value: { name: 'test' } + }, + { + key: 60, + value: null + }, + { + key: 30, + value: 'something' + }, + { + key: 90, + value: undefined + }, + { + key: 80, + value: undefined + }, + { + key: 50, + value: undefined + }, + { + key: 40, + value: undefined + } + ]); + }); + }); + describe('.extractRoot()', () => { it('should extract the root (min key) from the heap', () => { expect(minHeap.extractRoot().serialize()).to.deep.equal({