From d37adadf44537cff90278e061849281595aa2145 Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <mikhail.maksyutin@gmail.com> Date: Fri, 1 Jun 2018 15:19:27 +0300 Subject: [PATCH 1/8] Fix LinkedList --- src/data-structures/linked-list/LinkedList.js | 2 +- src/data-structures/linked-list/__test__/LinkedList.test.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/data-structures/linked-list/LinkedList.js b/src/data-structures/linked-list/LinkedList.js index b428ad7395..4e82ab0d7f 100644 --- a/src/data-structures/linked-list/LinkedList.js +++ b/src/data-structures/linked-list/LinkedList.js @@ -60,7 +60,7 @@ export default class LinkedList { let deletedNode = null; // If the head must be deleted then make 2nd node to be a head. - if (this.compare.equal(this.head.value, value)) { + while (this.head && this.compare.equal(this.head.value, value)) { deletedNode = this.head; this.head = this.head.next; } diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index 1b938e1b10..61f018fee6 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -32,6 +32,7 @@ describe('LinkedList', () => { expect(linkedList.delete(5)).toBeNull(); + linkedList.append(1); linkedList.append(1); linkedList.append(2); linkedList.append(3); @@ -45,10 +46,10 @@ describe('LinkedList', () => { const deletedNode = linkedList.delete(3); expect(deletedNode.value).toBe(3); - expect(linkedList.toString()).toBe('1,2,4,5'); + expect(linkedList.toString()).toBe('1,1,2,4,5'); linkedList.delete(3); - expect(linkedList.toString()).toBe('1,2,4,5'); + expect(linkedList.toString()).toBe('1,1,2,4,5'); linkedList.delete(1); expect(linkedList.toString()).toBe('2,4,5'); From 8d85d3d443d34ff383fd52762f8efff059aac85c Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Sun, 3 Jun 2018 14:17:42 +0300 Subject: [PATCH 2/8] Fix the prepend method for the LinkedList --- src/data-structures/linked-list/LinkedList.js | 8 +++++++- .../linked-list/__test__/LinkedList.test.js | 8 ++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/data-structures/linked-list/LinkedList.js b/src/data-structures/linked-list/LinkedList.js index 4e82ab0d7f..7d330f7bfd 100644 --- a/src/data-structures/linked-list/LinkedList.js +++ b/src/data-structures/linked-list/LinkedList.js @@ -21,7 +21,13 @@ export default class LinkedList { */ prepend(value) { // Make new node to be a head. - this.head = new LinkedListNode(value, this.head); + const newNode = new LinkedListNode(value, this.head); + this.head = newNode; + + // If there is no tail yet let's make new node a tail. + if (!this.tail) { + this.tail = newNode; + } return this; } diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index 61f018fee6..384e44fa5b 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -21,10 +21,14 @@ describe('LinkedList', () => { it('should prepend node to linked list', () => { const linkedList = new LinkedList(); - linkedList.append(1); linkedList.prepend(2); + expect(linkedList.head.toString()).toBe('2'); + expect(linkedList.tail.toString()).toBe('2'); + + linkedList.append(1); + linkedList.prepend(3); - expect(linkedList.toString()).toBe('2,1'); + expect(linkedList.toString()).toBe('3,2,1'); }); it('should delete node by value from linked list', () => { From efe4f8119224e95c170c6c51ed038c6cf6a2b46c Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Mon, 4 Jun 2018 11:38:26 +0300 Subject: [PATCH 3/8] Fix the remove method for the MinHeap --- src/data-structures/heap/MinHeap.js | 2 +- .../heap/__test__/MinHeap.test.js | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/data-structures/heap/MinHeap.js b/src/data-structures/heap/MinHeap.js index bf23f415dd..5f32f53f74 100644 --- a/src/data-structures/heap/MinHeap.js +++ b/src/data-structures/heap/MinHeap.js @@ -141,8 +141,8 @@ export default class MinHeap { */ remove(item, customFindingComparator) { // Find number of items to remove. - const numberOfItemsToRemove = this.find(item).length; const customComparator = customFindingComparator || this.compare; + const numberOfItemsToRemove = this.find(item, customComparator).length; for (let iteration = 0; iteration < numberOfItemsToRemove; iteration += 1) { // We need to find item index to remove each time after removal since diff --git a/src/data-structures/heap/__test__/MinHeap.test.js b/src/data-structures/heap/__test__/MinHeap.test.js index f4ce4ac381..b2b8a7b157 100644 --- a/src/data-structures/heap/__test__/MinHeap.test.js +++ b/src/data-structures/heap/__test__/MinHeap.test.js @@ -1,4 +1,5 @@ import MinHeap from '../MinHeap'; +import Comparator from '../../../utils/comparator/Comparator'; describe('MinHeap', () => { it('should create an empty min heap', () => { @@ -147,4 +148,25 @@ describe('MinHeap', () => { expect(minHeap.remove(3).toString()).toEqual('4'); expect(minHeap.remove(4).toString()).toEqual(''); }); + + it('should be possible to remove items from heap with custom finding comparator', () => { + const minHeap = new MinHeap(); + minHeap.add('dddd'); + minHeap.add('ccc'); + minHeap.add('bb'); + minHeap.add('a'); + + expect(minHeap.toString()).toBe('a,bb,ccc,dddd'); + + const comparator = new Comparator((a, b) => { + if (a.length === b.length) { + return 0; + } + + return a.length < b.length ? -1 : 1; + }); + + minHeap.remove('hey', comparator); + expect(minHeap.toString()).toBe('a,bb,dddd'); + }); }); From eae4e5c13bc6e6140dc813e1f2cb0526eb3d1d55 Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Wed, 13 Jun 2018 17:53:47 +0300 Subject: [PATCH 4/8] Correct a comment --- src/data-structures/tree/BinaryTreeNode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/tree/BinaryTreeNode.js b/src/data-structures/tree/BinaryTreeNode.js index 71e7ae0d3f..9205e4820e 100644 --- a/src/data-structures/tree/BinaryTreeNode.js +++ b/src/data-structures/tree/BinaryTreeNode.js @@ -69,7 +69,7 @@ export default class BinaryTreeNode { return undefined; } - // Check if grand-parent has more than two children. + // Check if grand-parent has two children. if (!this.parent.parent.left || !this.parent.parent.right) { return undefined; } From a2c30129afbbb591c790ec659df7f723feccc0a5 Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Tue, 19 Jun 2018 10:57:02 +0300 Subject: [PATCH 5/8] Fix BST removal method --- .../binary-search-tree/BinarySearchTreeNode.js | 18 +++++++++++------- .../__test__/BinarySearchTreeNode.test.js | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js b/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js index 9ad74483da..06d99e431b 100644 --- a/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js +++ b/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js @@ -94,8 +94,13 @@ export default class BinarySearchTreeNode extends BinaryTreeNode { if (!nodeToRemove.left && !nodeToRemove.right) { // Node is a leaf and thus has no children. - // Just remove the pointer to this node from the parent node. - parent.removeChild(nodeToRemove); + if (parent) { + // Node has a parent. Just remove the pointer to this node from the parent. + parent.removeChild(nodeToRemove); + } else { + // Node has no parent. Just erase current node value. + nodeToRemove.value = null; + } } else if (nodeToRemove.left && nodeToRemove.right) { // Node has two children. // Find the next biggest value (minimum value in the right branch) @@ -113,11 +118,10 @@ export default class BinarySearchTreeNode extends BinaryTreeNode { } else { // Node has only one child. // Make this child to be a direct child of current node's parent. - if (nodeToRemove.left) { - parent.replaceChild(nodeToRemove, nodeToRemove.left); - } else { - parent.replaceChild(nodeToRemove, nodeToRemove.right); - } + const child = nodeToRemove.left || nodeToRemove.right; + nodeToRemove.value = child.value; + nodeToRemove.setLeft(child.left); + nodeToRemove.setRight(child.right); } return true; diff --git a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js index a353c1f1e1..63b9d999d6 100644 --- a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js +++ b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js @@ -185,6 +185,21 @@ describe('BinarySearchTreeNode', () => { expect(bstRootNode.toString()).toBe('30'); }); + it('should remove node with no parent', () => { + const bstRootNode = new BinarySearchTreeNode(); + expect(bstRootNode.toString()).toBe(''); + + bstRootNode.insert(1); + bstRootNode.insert(2); + expect(bstRootNode.toString()).toBe('1,2'); + + bstRootNode.remove(1); + expect(bstRootNode.toString()).toBe('2'); + + bstRootNode.remove(2); + expect(bstRootNode.toString()).toBe(''); + }); + it('should throw error when trying to remove not existing node', () => { const bstRootNode = new BinarySearchTreeNode(); From 35f7b89e16aabd934660356298f2e95e350c74e1 Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Mon, 25 Jun 2018 11:05:54 +0300 Subject: [PATCH 6/8] Fix the findEdge method of the graph --- src/data-structures/graph/Graph.js | 3 +++ src/data-structures/graph/__test__/Graph.test.js | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/data-structures/graph/Graph.js b/src/data-structures/graph/Graph.js index e2ef20b7e0..8e603c389b 100644 --- a/src/data-structures/graph/Graph.js +++ b/src/data-structures/graph/Graph.js @@ -115,6 +115,9 @@ export default class Graph { */ findEdge(startVertex, endVertex) { const vertex = this.getVertexByKey(startVertex.getKey()); + if (!vertex) { + return null; + } return vertex.findEdge(endVertex); } diff --git a/src/data-structures/graph/__test__/Graph.test.js b/src/data-structures/graph/__test__/Graph.test.js index 1c6592ba55..be6e9d7fb2 100644 --- a/src/data-structures/graph/__test__/Graph.test.js +++ b/src/data-structures/graph/__test__/Graph.test.js @@ -87,9 +87,11 @@ describe('Graph', () => { const graphEdgeAB = graph.findEdge(vertexA, vertexB); const graphEdgeBA = graph.findEdge(vertexB, vertexA); - const graphEdgeAC = graph.findEdge(vertexB, vertexC); + const graphEdgeAC = graph.findEdge(vertexA, vertexC); + const graphEdgeCA = graph.findEdge(vertexC, vertexA); expect(graphEdgeAC).toBeNull(); + expect(graphEdgeCA).toBeNull(); expect(graphEdgeAB).toEqual(edgeAB); expect(graphEdgeBA).toEqual(edgeAB); expect(graphEdgeAB.weight).toBe(10); @@ -108,9 +110,11 @@ describe('Graph', () => { const graphEdgeAB = graph.findEdge(vertexA, vertexB); const graphEdgeBA = graph.findEdge(vertexB, vertexA); - const graphEdgeAC = graph.findEdge(vertexB, vertexC); + const graphEdgeAC = graph.findEdge(vertexA, vertexC); + const graphEdgeCA = graph.findEdge(vertexC, vertexA); expect(graphEdgeAC).toBeNull(); + expect(graphEdgeCA).toBeNull(); expect(graphEdgeBA).toBeNull(); expect(graphEdgeAB).toEqual(edgeAB); expect(graphEdgeAB.weight).toBe(10); From 48790e9546ead6c9d211ff868d395846bc1e479f Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Mon, 25 Jun 2018 18:16:43 +0300 Subject: [PATCH 7/8] Fix the value returned by DisjointSet union --- src/data-structures/disjoint-set/DisjointSet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/disjoint-set/DisjointSet.js b/src/data-structures/disjoint-set/DisjointSet.js index 2952f0a1b8..2fe3c25c3c 100644 --- a/src/data-structures/disjoint-set/DisjointSet.js +++ b/src/data-structures/disjoint-set/DisjointSet.js @@ -70,7 +70,7 @@ export default class DisjointSet { // If rootB's tree is bigger then make rootB to be a new root. rootB.addChild(rootA); - return rootB.getKey(); + return this; } // If rootA's tree is bigger then make rootA to be a new root. From 3331115575501d8bec469d1cee228110f1d16f52 Mon Sep 17 00:00:00 2001 From: "m.maksyutin" <m.maksyutin@gmail.com> Date: Thu, 28 Jun 2018 16:37:40 +0300 Subject: [PATCH 8/8] Add recursive factorial function --- .../factorial/__test__/factorialRecursive.test.js | 11 +++++++++++ src/algorithms/math/factorial/factorialRecursive.js | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 src/algorithms/math/factorial/__test__/factorialRecursive.test.js create mode 100644 src/algorithms/math/factorial/factorialRecursive.js diff --git a/src/algorithms/math/factorial/__test__/factorialRecursive.test.js b/src/algorithms/math/factorial/__test__/factorialRecursive.test.js new file mode 100644 index 0000000000..9029faee0a --- /dev/null +++ b/src/algorithms/math/factorial/__test__/factorialRecursive.test.js @@ -0,0 +1,11 @@ +import factorialRecursive from '../factorialRecursive'; + +describe('factorialRecursive', () => { + it('should calculate factorial', () => { + expect(factorialRecursive(0)).toBe(1); + expect(factorialRecursive(1)).toBe(1); + expect(factorialRecursive(5)).toBe(120); + expect(factorialRecursive(8)).toBe(40320); + expect(factorialRecursive(10)).toBe(3628800); + }); +}); diff --git a/src/algorithms/math/factorial/factorialRecursive.js b/src/algorithms/math/factorial/factorialRecursive.js new file mode 100644 index 0000000000..e2b4aec6c9 --- /dev/null +++ b/src/algorithms/math/factorial/factorialRecursive.js @@ -0,0 +1,7 @@ +/** + * @param {number} number + * @return {number} + */ +export default function factorialRecursive(number) { + return number > 1 ? number * factorialRecursive(number - 1) : 1; +}