diff --git a/.gitignore b/.gitignore
index 1890e8bd0e..08f570ad06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,5 @@ SpringDataInjectionDemo/.mvn/wrapper/maven-wrapper.properties
spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties
spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties
+*.springBeans
+
diff --git a/README.md b/README.md
index f0d3d29da7..25398d1d39 100644
--- a/README.md
+++ b/README.md
@@ -23,4 +23,4 @@ Any IDE can be used to work with the projects, but if you're using Eclipse, cons
CI - Jenkins
================================
-This tutorials project is being built **[>> HERE](https://rest-security.ci.cloudbees.com/job/tutorials/)**
+This tutorials project is being built **[>> HERE](https://rest-security.ci.cloudbees.com/job/github%20projects%20Jobs/job/tutorials/)**
diff --git a/algorithms/README.md b/algorithms/README.md
index dc12b528da..8cf4c35b68 100644
--- a/algorithms/README.md
+++ b/algorithms/README.md
@@ -8,3 +8,4 @@
- [Check If a Number Is Prime in Java](http://www.baeldung.com/java-prime-numbers)
- [Example of Hill Climbing Algorithm](http://www.baeldung.com/java-hill-climbing-algorithm)
- [Monte Carlo Tree Search for Tic-Tac-Toe Game](http://www.baeldung.com/java-monte-carlo-tree-search)
+- [String Search Algorithms for Large Texts](http://www.baeldung.com/java-full-text-search-algorithms)
diff --git a/algorithms/pom.xml b/algorithms/pom.xml
index 967bcbc706..e972f39494 100644
--- a/algorithms/pom.xml
+++ b/algorithms/pom.xml
@@ -34,6 +34,11 @@
jenetics
3.7.0
+
+ org.jgrapht
+ jgrapht-core
+ 1.0.1
+
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java b/algorithms/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
new file mode 100644
index 0000000000..5b2ac49d4e
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/binarysearch/BinarySearch.java
@@ -0,0 +1,55 @@
+package com.baeldung.algorithms.binarysearch;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class BinarySearch {
+
+ public int runBinarySearchIteratively(int[] sortedArray, int key, int low, int high) {
+
+ int index = Integer.MAX_VALUE;
+
+ while (low <= high) {
+
+ int mid = (low + high) / 2;
+
+ if (sortedArray[mid] < key) {
+ low = mid + 1;
+ } else if (sortedArray[mid] > key) {
+ high = mid - 1;
+ } else if (sortedArray[mid] == key) {
+ index = mid;
+ break;
+ }
+ }
+ return index;
+ }
+
+ public int runBinarySearchRecursively(int[] sortedArray, int key, int low, int high) {
+
+ int middle = (low + high) / 2;
+ if (high < low) {
+ return -1;
+ }
+
+ if (key == sortedArray[middle]) {
+ return middle;
+ } else if (key < sortedArray[middle]) {
+ return runBinarySearchRecursively(sortedArray, key, low, middle - 1);
+ } else {
+ return runBinarySearchRecursively(sortedArray, key, middle + 1, high);
+ }
+ }
+
+ public int runBinarySearchUsingJavaArrays(int[] sortedArray, Integer key) {
+ int index = Arrays.binarySearch(sortedArray, key);
+ return index;
+ }
+
+ public int runBinarySearchUsingJavaCollections(List sortedList, Integer key) {
+ int index = Collections.binarySearch(sortedList, key);
+ return index;
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForce.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForce.java
new file mode 100644
index 0000000000..1df425ad2e
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForce.java
@@ -0,0 +1,38 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class CycleDetectionBruteForce {
+
+ public static CycleDetectionResult detectCycle(Node head) {
+ if (head == null) {
+ return new CycleDetectionResult<>(false, null);
+ }
+
+ Node it1 = head;
+ int nodesTraversedByOuter = 0;
+ while (it1 != null && it1.next != null) {
+ it1 = it1.next;
+ nodesTraversedByOuter++;
+
+ int x = nodesTraversedByOuter;
+ Node it2 = head;
+ int noOfTimesCurrentNodeVisited = 0;
+
+ while (x > 0) {
+ it2 = it2.next;
+
+ if (it2 == it1) {
+ noOfTimesCurrentNodeVisited++;
+ }
+
+ if (noOfTimesCurrentNodeVisited == 2) {
+ return new CycleDetectionResult<>(true, it1);
+ }
+
+ x--;
+ }
+ }
+
+ return new CycleDetectionResult<>(false, null);
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIterators.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIterators.java
new file mode 100644
index 0000000000..ab088de44a
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIterators.java
@@ -0,0 +1,25 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class CycleDetectionByFastAndSlowIterators {
+
+ public static CycleDetectionResult detectCycle(Node head) {
+ if (head == null) {
+ return new CycleDetectionResult<>(false, null);
+ }
+
+ Node slow = head;
+ Node fast = head;
+
+ while (fast != null && fast.next != null) {
+ slow = slow.next;
+ fast = fast.next.next;
+
+ if (slow == fast) {
+ return new CycleDetectionResult<>(true, fast);
+ }
+ }
+
+ return new CycleDetectionResult<>(false, null);
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashing.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashing.java
new file mode 100644
index 0000000000..90d5ecd711
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashing.java
@@ -0,0 +1,27 @@
+package com.baeldung.algorithms.linkedlist;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class CycleDetectionByHashing {
+
+ public static CycleDetectionResult detectCycle(Node head) {
+ if (head == null) {
+ return new CycleDetectionResult<>(false, null);
+ }
+
+ Set> set = new HashSet<>();
+ Node node = head;
+
+ while (node != null) {
+ if (set.contains(node)) {
+ return new CycleDetectionResult<>(true, node);
+ }
+ set.add(node);
+ node = node.next;
+ }
+
+ return new CycleDetectionResult<>(false, null);
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionResult.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionResult.java
new file mode 100644
index 0000000000..e7556311b3
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleDetectionResult.java
@@ -0,0 +1,12 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class CycleDetectionResult {
+ boolean cycleExists;
+ Node node;
+
+ public CycleDetectionResult(boolean cycleExists, Node node) {
+ super();
+ this.cycleExists = cycleExists;
+ this.node = node;
+ }
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForce.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForce.java
new file mode 100644
index 0000000000..a2bfaee9a1
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalBruteForce.java
@@ -0,0 +1,56 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class CycleRemovalBruteForce {
+
+ public static boolean detectAndRemoveCycle(Node head) {
+ CycleDetectionResult result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
+
+ if (result.cycleExists) {
+ removeCycle(result.node, head);
+ }
+
+ return result.cycleExists;
+ }
+
+ /**
+ * @param loopNodeParam - reference to the node where Flyods cycle
+ * finding algorithm ends, i.e. the fast and the slow iterators
+ * meet.
+ * @param head - reference to the head of the list
+ */
+ private static void removeCycle(Node loopNodeParam, Node head) {
+ Node it = head;
+
+ while (it != null) {
+ if (isNodeReachableFromLoopNode(it, loopNodeParam)) {
+ Node loopStart = it;
+ findEndNodeAndBreakCycle(loopStart);
+ break;
+ }
+ it = it.next;
+ }
+ }
+
+ private static boolean isNodeReachableFromLoopNode(Node it, Node loopNodeParam) {
+ Node loopNode = loopNodeParam;
+
+ do {
+ if (it == loopNode) {
+ return true;
+ }
+ loopNode = loopNode.next;
+ } while (loopNode.next != loopNodeParam);
+
+ return false;
+ }
+
+ private static void findEndNodeAndBreakCycle(Node loopStartParam) {
+ Node loopStart = loopStartParam;
+
+ while (loopStart.next != loopStartParam) {
+ loopStart = loopStart.next;
+ }
+
+ loopStart.next = null;
+ }
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodes.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodes.java
new file mode 100644
index 0000000000..d8db37fc4c
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalByCountingLoopNodes.java
@@ -0,0 +1,44 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class CycleRemovalByCountingLoopNodes {
+
+ public static boolean detectAndRemoveCycle(Node head) {
+ CycleDetectionResult result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
+
+ if (result.cycleExists) {
+ removeCycle(result.node, head);
+ }
+
+ return result.cycleExists;
+ }
+
+ private static void removeCycle(Node loopNodeParam, Node head) {
+ int cycleLength = calculateCycleLength(loopNodeParam);
+ Node cycleLengthAdvancedIterator = head;
+ Node it = head;
+
+ for (int i = 0; i < cycleLength; i++) {
+ cycleLengthAdvancedIterator = cycleLengthAdvancedIterator.next;
+ }
+
+ while (it.next != cycleLengthAdvancedIterator.next) {
+ it = it.next;
+ cycleLengthAdvancedIterator = cycleLengthAdvancedIterator.next;
+ }
+
+ cycleLengthAdvancedIterator.next = null;
+ }
+
+ private static int calculateCycleLength(Node loopNodeParam) {
+ Node loopNode = loopNodeParam;
+ int length = 1;
+
+ while (loopNode.next != loopNodeParam) {
+ length++;
+ loopNode = loopNode.next;
+ }
+
+ return length;
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodes.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodes.java
new file mode 100644
index 0000000000..b979f7f677
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/CycleRemovalWithoutCountingLoopNodes.java
@@ -0,0 +1,27 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class CycleRemovalWithoutCountingLoopNodes {
+
+ public static boolean detectAndRemoveCycle(Node head) {
+ CycleDetectionResult result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
+
+ if (result.cycleExists) {
+ removeCycle(result.node, head);
+ }
+
+ return result.cycleExists;
+ }
+
+ private static void removeCycle(Node meetingPointParam, Node head) {
+ Node loopNode = meetingPointParam;
+ Node it = head;
+
+ while (loopNode.next != it.next) {
+ it = it.next;
+ loopNode = loopNode.next;
+ }
+
+ loopNode.next = null;
+ }
+
+}
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/Node.java b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/Node.java
new file mode 100644
index 0000000000..4add22c77d
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/linkedlist/Node.java
@@ -0,0 +1,38 @@
+package com.baeldung.algorithms.linkedlist;
+
+public class Node {
+ T data;
+ Node next;
+
+ public static Node createNewNode(T data, Node next) {
+ Node node = new Node();
+ node.data = data;
+ node.next = next;
+ return node;
+ }
+
+ public static void traverseList(Node root) {
+ if (root == null) {
+ return;
+ }
+
+ Node node = root;
+ while (node != null) {
+ System.out.println(node.data);
+ node = node.next;
+ }
+ }
+
+ public static Node getTail(Node root) {
+ if (root == null) {
+ return null;
+ }
+
+ Node node = root;
+ while (node.next != null) {
+ node = node.next;
+ }
+ return node;
+ }
+
+}
\ No newline at end of file
diff --git a/algorithms/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java b/algorithms/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java
new file mode 100755
index 0000000000..45ac53e039
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/string/search/StringSearchAlgorithms.java
@@ -0,0 +1,194 @@
+package com.baeldung.algorithms.string.search;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+public class StringSearchAlgorithms {
+ public static long getBiggerPrime(int m) {
+ BigInteger prime = BigInteger.probablePrime(getNumberOfBits(m) + 1, new Random());
+ return prime.longValue();
+ }
+
+ public static long getLowerPrime(long number) {
+ BigInteger prime = BigInteger.probablePrime(getNumberOfBits(number) - 1, new Random());
+ return prime.longValue();
+ }
+
+ private static int getNumberOfBits(final int number) {
+ return Integer.SIZE - Integer.numberOfLeadingZeros(number);
+ }
+
+ private static int getNumberOfBits(final long number) {
+ return Long.SIZE - Long.numberOfLeadingZeros(number);
+ }
+
+ public static int simpleTextSearch(char[] pattern, char[] text) {
+ int patternSize = pattern.length;
+ int textSize = text.length;
+
+ int i = 0;
+
+ while ((i + patternSize) <= textSize) {
+ int j = 0;
+ while (text[i + j] == pattern[j]) {
+ j += 1;
+ if (j >= patternSize)
+ return i;
+ }
+ i += 1;
+ }
+
+ return -1;
+ }
+
+ public static int RabinKarpMethod(char[] pattern, char[] text) {
+ int patternSize = pattern.length; // m
+ int textSize = text.length; // n
+
+ long prime = getBiggerPrime(patternSize);
+
+ long r = 1;
+ for (int i = 0; i < patternSize - 1; i++) {
+ r *= 2;
+ r = r % prime;
+ }
+
+ long[] t = new long[textSize];
+ t[0] = 0;
+
+ long pfinger = 0;
+
+ for (int j = 0; j < patternSize; j++) {
+ t[0] = (2 * t[0] + text[j]) % prime;
+ pfinger = (2 * pfinger + pattern[j]) % prime;
+ }
+
+ int i = 0;
+ boolean passed = false;
+
+ int diff = textSize - patternSize;
+ for (i = 0; i <= diff; i++) {
+ if (t[i] == pfinger) {
+ passed = true;
+ for (int k = 0; k < patternSize; k++) {
+ if (text[i + k] != pattern[k]) {
+ passed = false;
+ break;
+ }
+ }
+
+ if (passed) {
+ return i;
+ }
+ }
+
+ if (i < diff) {
+ long value = 2 * (t[i] - r * text[i]) + text[i + patternSize];
+ t[i + 1] = ((value % prime) + prime) % prime;
+ }
+ }
+ return -1;
+
+ }
+
+ public static int KnuthMorrisPrattSearch(char[] pattern, char[] text) {
+ int patternSize = pattern.length; // m
+ int textSize = text.length; // n
+
+ int i = 0, j = 0;
+
+ int[] shift = KnuthMorrisPrattShift(pattern);
+
+ while ((i + patternSize) <= textSize) {
+ while (text[i + j] == pattern[j]) {
+ j += 1;
+ if (j >= patternSize)
+ return i;
+ }
+
+ if (j > 0) {
+ i += shift[j - 1];
+ j = Math.max(j - shift[j - 1], 0);
+ } else {
+ i++;
+ j = 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int[] KnuthMorrisPrattShift(char[] pattern) {
+ int patternSize = pattern.length;
+
+ int[] shift = new int[patternSize];
+ shift[0] = 1;
+
+ int i = 1, j = 0;
+
+ while ((i + j) < patternSize) {
+ if (pattern[i + j] == pattern[j]) {
+ shift[i + j] = i;
+ j++;
+ } else {
+ if (j == 0)
+ shift[i] = i + 1;
+
+ if (j > 0) {
+ i = i + shift[j - 1];
+ j = Math.max(j - shift[j - 1], 0);
+ } else {
+ i = i + 1;
+ j = 0;
+ }
+ }
+ }
+ return shift;
+ }
+
+ public static int BoyerMooreHorspoolSimpleSearch(char[] pattern, char[] text) {
+ int patternSize = pattern.length;
+ int textSize = text.length;
+
+ int i = 0, j = 0;
+
+ while ((i + patternSize) <= textSize) {
+ j = patternSize - 1;
+ while (text[i + j] == pattern[j]) {
+ j--;
+ if (j < 0)
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ public static int BoyerMooreHorspoolSearch(char[] pattern, char[] text) {
+
+ int shift[] = new int[256];
+
+ for (int k = 0; k < 256; k++) {
+ shift[k] = pattern.length;
+ }
+
+ for (int k = 0; k < pattern.length - 1; k++) {
+ shift[pattern[k]] = pattern.length - 1 - k;
+ }
+
+ int i = 0, j = 0;
+
+ while ((i + pattern.length) <= text.length) {
+ j = pattern.length - 1;
+
+ while (text[i + j] == pattern[j]) {
+ j -= 1;
+ if (j < 0)
+ return i;
+ }
+
+ i = i + shift[text[i + pattern.length - 1]];
+
+ }
+ return -1;
+ }
+}
diff --git a/algorithms/src/test/java/algorithms/StringSearchAlgorithmsTest.java b/algorithms/src/test/java/algorithms/StringSearchAlgorithmsTest.java
new file mode 100755
index 0000000000..e260cd7e5b
--- /dev/null
+++ b/algorithms/src/test/java/algorithms/StringSearchAlgorithmsTest.java
@@ -0,0 +1,25 @@
+package algorithms;
+
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.baeldung.algorithms.string.search.StringSearchAlgorithms;
+
+public class StringSearchAlgorithmsTest {
+
+
+ @Test
+ public void testStringSearchAlgorithms(){
+ String text = "This is some nice text.";
+ String pattern = "some";
+
+ int realPosition = text.indexOf(pattern);
+ Assert.assertTrue(realPosition == StringSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == StringSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == StringSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == StringSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray()));
+ Assert.assertTrue(realPosition == StringSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray()));
+ }
+
+}
diff --git a/algorithms/src/test/java/algorithms/binarysearch/BinarySearchTest.java b/algorithms/src/test/java/algorithms/binarysearch/BinarySearchTest.java
new file mode 100644
index 0000000000..959f47a275
--- /dev/null
+++ b/algorithms/src/test/java/algorithms/binarysearch/BinarySearchTest.java
@@ -0,0 +1,43 @@
+package algorithms.binarysearch;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import com.baeldung.algorithms.binarysearch.BinarySearch;
+
+public class BinarySearchTest {
+
+ int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 };
+ int key = 6;
+ int expectedIndexForSearchKey = 7;
+ int low = 0;
+ int high = sortedArray.length - 1;
+ List sortedList = Arrays.asList(0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9);
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunIterativelyForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchIteratively(sortedArray, key, low, high));
+ }
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunRecursivelyForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchRecursively(sortedArray, key, low, high));
+ }
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunUsingArraysClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaArrays(sortedArray, key));
+ }
+
+ @Test
+ public void givenASortedListOfIntegers_whenBinarySearchRunUsingCollectionsClassStaticMethodForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearchUsingJavaCollections(sortedList, key));
+ }
+
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceTest.java b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceTest.java
new file mode 100644
index 0000000000..7f9b8acdbd
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionBruteForceTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.algorithms.linkedlist;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(value = Parameterized.class)
+public class CycleDetectionBruteForceTest extends CycleDetectionTestBase {
+ boolean cycleExists;
+ Node head;
+
+ public CycleDetectionBruteForceTest(Node head, boolean cycleExists) {
+ super();
+ this.cycleExists = cycleExists;
+ this.head = head;
+ }
+
+ @Test
+ public void givenList_detectLoop() {
+ Assert.assertEquals(cycleExists, CycleDetectionBruteForce.detectCycle(head).cycleExists);
+ }
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsTest.java b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsTest.java
new file mode 100644
index 0000000000..17d339bc33
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByFastAndSlowIteratorsTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.algorithms.linkedlist;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(value = Parameterized.class)
+public class CycleDetectionByFastAndSlowIteratorsTest extends CycleDetectionTestBase {
+ boolean cycleExists;
+ Node head;
+
+ public CycleDetectionByFastAndSlowIteratorsTest(Node head, boolean cycleExists) {
+ super();
+ this.cycleExists = cycleExists;
+ this.head = head;
+ }
+
+ @Test
+ public void givenList_detectLoop() {
+ Assert.assertEquals(cycleExists, CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists);
+ }
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingTest.java b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingTest.java
new file mode 100644
index 0000000000..73a2cc7861
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionByHashingTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.algorithms.linkedlist;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(value = Parameterized.class)
+public class CycleDetectionByHashingTest extends CycleDetectionTestBase {
+ boolean cycleExists;
+ Node head;
+
+ public CycleDetectionByHashingTest(Node head, boolean cycleExists) {
+ super();
+ this.cycleExists = cycleExists;
+ this.head = head;
+ }
+
+ @Test
+ public void givenList_detectLoop() {
+ Assert.assertEquals(cycleExists, CycleDetectionByHashing.detectCycle(head).cycleExists);
+ }
+}
diff --git a/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java
new file mode 100644
index 0000000000..51906de8e5
--- /dev/null
+++ b/algorithms/src/test/java/com/baeldung/algorithms/linkedlist/CycleDetectionTestBase.java
@@ -0,0 +1,62 @@
+package com.baeldung.algorithms.linkedlist;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.runners.Parameterized.Parameters;
+
+public class CycleDetectionTestBase {
+
+ @Parameters
+ public static Collection