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;
+}