JAVA-12097: renamed algorithms-module to algorithms-modules
This commit is contained in:
15
algorithms-modules/algorithms-searching/README.md
Normal file
15
algorithms-modules/algorithms-searching/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## Algorithms - Searching
|
||||
|
||||
This module contains articles about searching algorithms.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Binary Search Algorithm in Java](https://www.baeldung.com/java-binary-search)
|
||||
- [Depth First Search in Java](https://www.baeldung.com/java-depth-first-search)
|
||||
- [Interpolation Search in Java](https://www.baeldung.com/java-interpolation-search)
|
||||
- [Breadth-First Search Algorithm in Java](https://www.baeldung.com/java-breadth-first-search)
|
||||
- [String Search Algorithms for Large Texts with Java](https://www.baeldung.com/java-full-text-search-algorithms)
|
||||
- [Monte Carlo Tree Search for Tic-Tac-Toe Game in Java](https://www.baeldung.com/java-monte-carlo-tree-search)
|
||||
- [Range Search Algorithm in Java](https://www.baeldung.com/java-range-search)
|
||||
- [Fast Pattern Matching of Strings Using Suffix Tree in Java](https://www.baeldung.com/java-pattern-matching-suffix-tree)
|
||||
- [Find the Kth Smallest Element in Two Sorted Arrays in Java](https://www.baeldung.com/java-kth-smallest-element-in-sorted-arrays)
|
||||
26
algorithms-modules/algorithms-searching/pom.xml
Normal file
26
algorithms-modules/algorithms-searching/pom.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>algorithms-searching</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>algorithms-searching</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>algorithms-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<finalName>algorithms-searching</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -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 - low) / 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 - low) / 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<Integer> sortedList, Integer key) {
|
||||
int index = Collections.binarySearch(sortedList, key);
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.baeldung.algorithms.breadthfirstsearch;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BreadthFirstSearchAlgorithm {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BreadthFirstSearchAlgorithm.class);
|
||||
|
||||
public static <T> Optional<Tree<T>> search(T value, Tree<T> root) {
|
||||
Queue<Tree<T>> queue = new ArrayDeque<>();
|
||||
queue.add(root);
|
||||
|
||||
Tree<T> currentNode;
|
||||
while (!queue.isEmpty()) {
|
||||
currentNode = queue.remove();
|
||||
LOGGER.debug("Visited node with value: {}", currentNode.getValue());
|
||||
|
||||
if (currentNode.getValue().equals(value)) {
|
||||
return Optional.of(currentNode);
|
||||
} else {
|
||||
queue.addAll(currentNode.getChildren());
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static <T> Optional<Node<T>> search(T value, Node<T> start) {
|
||||
Queue<Node<T>> queue = new ArrayDeque<>();
|
||||
queue.add(start);
|
||||
|
||||
Node<T> currentNode;
|
||||
Set<Node<T>> alreadyVisited = new HashSet<>();
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
currentNode = queue.remove();
|
||||
LOGGER.debug("Visited node with value: {}", currentNode.getValue());
|
||||
|
||||
if (currentNode.getValue().equals(value)) {
|
||||
return Optional.of(currentNode);
|
||||
} else {
|
||||
alreadyVisited.add(currentNode);
|
||||
queue.addAll(currentNode.getNeighbors());
|
||||
queue.removeAll(alreadyVisited);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.algorithms.breadthfirstsearch;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Node<T> {
|
||||
|
||||
private T value;
|
||||
private Set<Node<T>> neighbors;
|
||||
|
||||
public Node(T value) {
|
||||
this.value = value;
|
||||
this.neighbors = new HashSet<>();
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Set<Node<T>> getNeighbors() {
|
||||
return Collections.unmodifiableSet(neighbors);
|
||||
}
|
||||
|
||||
public void connect(Node<T> node) {
|
||||
if (this == node) throw new IllegalArgumentException("Can't connect node to itself");
|
||||
this.neighbors.add(node);
|
||||
node.neighbors.add(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.baeldung.algorithms.breadthfirstsearch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Tree<T> {
|
||||
|
||||
private T value;
|
||||
private List<Tree<T>> children;
|
||||
|
||||
private Tree(T value) {
|
||||
this.value = value;
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static <T> Tree<T> of(T value) {
|
||||
return new Tree<>(value);
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public List<Tree<T>> getChildren() {
|
||||
return Collections.unmodifiableList(children);
|
||||
}
|
||||
|
||||
public Tree<T> addChild(T value) {
|
||||
Tree<T> newChild = new Tree<>(value);
|
||||
children.add(newChild);
|
||||
return newChild;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package com.baeldung.algorithms.dfs;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class BinaryTree {
|
||||
|
||||
Node root;
|
||||
|
||||
public void add(int value) {
|
||||
root = addRecursive(root, value);
|
||||
}
|
||||
|
||||
private Node addRecursive(Node current, int value) {
|
||||
|
||||
if (current == null) {
|
||||
return new Node(value);
|
||||
}
|
||||
|
||||
if (value < current.value) {
|
||||
current.left = addRecursive(current.left, value);
|
||||
} else if (value > current.value) {
|
||||
current.right = addRecursive(current.right, value);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return root == null;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return getSizeRecursive(root);
|
||||
}
|
||||
|
||||
private int getSizeRecursive(Node current) {
|
||||
return current == null ? 0 : getSizeRecursive(current.left) + 1 + getSizeRecursive(current.right);
|
||||
}
|
||||
|
||||
public boolean containsNode(int value) {
|
||||
return containsNodeRecursive(root, value);
|
||||
}
|
||||
|
||||
private boolean containsNodeRecursive(Node current, int value) {
|
||||
if (current == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == current.value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return value < current.value
|
||||
? containsNodeRecursive(current.left, value)
|
||||
: containsNodeRecursive(current.right, value);
|
||||
}
|
||||
|
||||
public void delete(int value) {
|
||||
root = deleteRecursive(root, value);
|
||||
}
|
||||
|
||||
private Node deleteRecursive(Node current, int value) {
|
||||
if (current == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value == current.value) {
|
||||
// Case 1: no children
|
||||
if (current.left == null && current.right == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Case 2: only 1 child
|
||||
if (current.right == null) {
|
||||
return current.left;
|
||||
}
|
||||
|
||||
if (current.left == null) {
|
||||
return current.right;
|
||||
}
|
||||
|
||||
// Case 3: 2 children
|
||||
int smallestValue = findSmallestValue(current.right);
|
||||
current.value = smallestValue;
|
||||
current.right = deleteRecursive(current.right, smallestValue);
|
||||
return current;
|
||||
}
|
||||
if (value < current.value) {
|
||||
current.left = deleteRecursive(current.left, value);
|
||||
return current;
|
||||
}
|
||||
|
||||
current.right = deleteRecursive(current.right, value);
|
||||
return current;
|
||||
}
|
||||
|
||||
private int findSmallestValue(Node root) {
|
||||
return root.left == null ? root.value : findSmallestValue(root.left);
|
||||
}
|
||||
|
||||
public void traverseInOrder(Node node) {
|
||||
if (node != null) {
|
||||
traverseInOrder(node.left);
|
||||
visit(node.value);
|
||||
traverseInOrder(node.right);
|
||||
}
|
||||
}
|
||||
|
||||
public void traversePreOrder(Node node) {
|
||||
if (node != null) {
|
||||
visit(node.value);
|
||||
traversePreOrder(node.left);
|
||||
traversePreOrder(node.right);
|
||||
}
|
||||
}
|
||||
|
||||
public void traversePostOrder(Node node) {
|
||||
if (node != null) {
|
||||
traversePostOrder(node.left);
|
||||
traversePostOrder(node.right);
|
||||
visit(node.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void traverseInOrderWithoutRecursion() {
|
||||
Stack<Node> stack = new Stack<>();
|
||||
Node current = root;
|
||||
|
||||
while (current != null || !stack.isEmpty()) {
|
||||
while (current != null) {
|
||||
stack.push(current);
|
||||
current = current.left;
|
||||
}
|
||||
|
||||
Node top = stack.pop();
|
||||
visit(top.value);
|
||||
current = top.right;
|
||||
}
|
||||
}
|
||||
|
||||
public void traversePreOrderWithoutRecursion() {
|
||||
Stack<Node> stack = new Stack<>();
|
||||
Node current;
|
||||
stack.push(root);
|
||||
while(! stack.isEmpty()) {
|
||||
current = stack.pop();
|
||||
visit(current.value);
|
||||
|
||||
if(current.right != null)
|
||||
stack.push(current.right);
|
||||
|
||||
if(current.left != null)
|
||||
stack.push(current.left);
|
||||
}
|
||||
}
|
||||
|
||||
public void traversePostOrderWithoutRecursion() {
|
||||
Stack<Node> stack = new Stack<>();
|
||||
Node prev = root;
|
||||
Node current;
|
||||
stack.push(root);
|
||||
|
||||
while (!stack.isEmpty()) {
|
||||
current = stack.peek();
|
||||
boolean hasChild = (current.left != null || current.right != null);
|
||||
boolean isPrevLastChild = (prev == current.right || (prev == current.left && current.right == null));
|
||||
|
||||
if (!hasChild || isPrevLastChild) {
|
||||
current = stack.pop();
|
||||
visit(current.value);
|
||||
prev = current;
|
||||
} else {
|
||||
if (current.right != null) {
|
||||
stack.push(current.right);
|
||||
}
|
||||
if (current.left != null) {
|
||||
stack.push(current.left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visit(int value) {
|
||||
System.out.print(" " + value);
|
||||
}
|
||||
|
||||
static class Node {
|
||||
int value;
|
||||
Node left;
|
||||
Node right;
|
||||
|
||||
Node(int value) {
|
||||
this.value = value;
|
||||
right = null;
|
||||
left = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.baeldung.algorithms.dfs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
public class Graph {
|
||||
|
||||
private Map<Integer, List<Integer>> adjVertices;
|
||||
|
||||
public Graph() {
|
||||
this.adjVertices = new HashMap<Integer, List<Integer>>();
|
||||
}
|
||||
|
||||
public void addVertex(int vertex) {
|
||||
adjVertices.putIfAbsent(vertex, new ArrayList<>());
|
||||
}
|
||||
|
||||
public void addEdge(int src, int dest) {
|
||||
adjVertices.get(src).add(dest);
|
||||
}
|
||||
|
||||
public void dfsWithoutRecursion(int start) {
|
||||
Stack<Integer> stack = new Stack<Integer>();
|
||||
boolean[] isVisited = new boolean[adjVertices.size()];
|
||||
stack.push(start);
|
||||
while (!stack.isEmpty()) {
|
||||
int current = stack.pop();
|
||||
if(!isVisited[current]){
|
||||
isVisited[current] = true;
|
||||
visit(current);
|
||||
for (int dest : adjVertices.get(current)) {
|
||||
if (!isVisited[dest])
|
||||
stack.push(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dfs(int start) {
|
||||
boolean[] isVisited = new boolean[adjVertices.size()];
|
||||
dfsRecursive(start, isVisited);
|
||||
}
|
||||
|
||||
private void dfsRecursive(int current, boolean[] isVisited) {
|
||||
isVisited[current] = true;
|
||||
visit(current);
|
||||
for (int dest : adjVertices.get(current)) {
|
||||
if (!isVisited[dest])
|
||||
dfsRecursive(dest, isVisited);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Integer> topologicalSort(int start) {
|
||||
LinkedList<Integer> result = new LinkedList<Integer>();
|
||||
boolean[] isVisited = new boolean[adjVertices.size()];
|
||||
topologicalSortRecursive(start, isVisited, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void topologicalSortRecursive(int current, boolean[] isVisited, LinkedList<Integer> result) {
|
||||
isVisited[current] = true;
|
||||
for (int dest : adjVertices.get(current)) {
|
||||
if (!isVisited[dest])
|
||||
topologicalSortRecursive(dest, isVisited, result);
|
||||
}
|
||||
result.addFirst(current);
|
||||
}
|
||||
|
||||
private void visit(int value) {
|
||||
System.out.print(" " + value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.baeldung.algorithms.interpolationsearch;
|
||||
|
||||
public class InterpolationSearch {
|
||||
|
||||
public static int interpolationSearch(int[] data, int item) {
|
||||
|
||||
int highEnd = (data.length - 1);
|
||||
int lowEnd = 0;
|
||||
|
||||
while (item >= data[lowEnd] && item <= data[highEnd] && lowEnd <= highEnd) {
|
||||
|
||||
int probe = lowEnd + (highEnd - lowEnd) * (item - data[lowEnd]) / (data[highEnd] - data[lowEnd]);
|
||||
|
||||
if (highEnd == lowEnd) {
|
||||
if (data[lowEnd] == item) {
|
||||
return lowEnd;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[probe] == item) {
|
||||
return probe;
|
||||
}
|
||||
|
||||
if (data[probe] < item) {
|
||||
lowEnd = probe + 1;
|
||||
} else {
|
||||
highEnd = probe - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.baeldung.algorithms.kthsmallest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
public class KthSmallest {
|
||||
|
||||
public static int findKthSmallestElement(int k, int[] list1, int[] list2) throws NoSuchElementException, IllegalArgumentException {
|
||||
|
||||
checkInput(k, list1, list2);
|
||||
|
||||
// we are looking for the minimum value
|
||||
if(k == 1) {
|
||||
return min(list1[0], list2[0]);
|
||||
}
|
||||
|
||||
// we are looking for the maximum value
|
||||
if(list1.length + list2.length == k) {
|
||||
return max(list1[list1.length-1], list2[list2.length-1]);
|
||||
}
|
||||
|
||||
// swap lists if needed to make sure we take at least one element from list1
|
||||
if(k <= list2.length && list2[k-1] < list1[0]) {
|
||||
int[] list1_ = list1;
|
||||
list1 = list2;
|
||||
list2 = list1_;
|
||||
}
|
||||
|
||||
// correct left boundary if k is bigger than the size of list2
|
||||
int left = k < list2.length ? 0 : k - list2.length - 1;
|
||||
|
||||
// the inital right boundary cannot exceed the list1
|
||||
int right = min(k-1, list1.length - 1);
|
||||
|
||||
int nElementsList1, nElementsList2;
|
||||
|
||||
// binary search
|
||||
do {
|
||||
nElementsList1 = ((left + right) / 2) + 1;
|
||||
nElementsList2 = k - nElementsList1;
|
||||
|
||||
if(nElementsList2 > 0) {
|
||||
if (list1[nElementsList1 - 1] > list2[nElementsList2 - 1]) {
|
||||
right = nElementsList1 - 2;
|
||||
} else {
|
||||
left = nElementsList1;
|
||||
}
|
||||
}
|
||||
} while(!kthSmallesElementFound(list1, list2, nElementsList1, nElementsList2));
|
||||
|
||||
return nElementsList2 == 0 ? list1[nElementsList1-1] : max(list1[nElementsList1-1], list2[nElementsList2-1]);
|
||||
}
|
||||
|
||||
private static boolean kthSmallesElementFound(int[] list1, int[] list2, int nElementsList1, int nElementsList2) {
|
||||
|
||||
// we do not take any element from the second list
|
||||
if(nElementsList2 < 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(list1[nElementsList1-1] == list2[nElementsList2-1]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(nElementsList1 == list1.length) {
|
||||
return list1[nElementsList1-1] <= list2[nElementsList2];
|
||||
}
|
||||
|
||||
if(nElementsList2 == list2.length) {
|
||||
return list2[nElementsList2-1] <= list1[nElementsList1];
|
||||
}
|
||||
|
||||
return list1[nElementsList1-1] <= list2[nElementsList2] && list2[nElementsList2-1] <= list1[nElementsList1];
|
||||
}
|
||||
|
||||
|
||||
private static void checkInput(int k, int[] list1, int[] list2) throws NoSuchElementException, IllegalArgumentException {
|
||||
|
||||
if(list1 == null || list2 == null || k < 1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if(list1.length == 0 || list2.length == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if(k > list1.length + list2.length) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKthElementSorted(int[] list1, int[] list2, int k) {
|
||||
|
||||
int length1 = list1.length, length2 = list2.length;
|
||||
int[] combinedArray = new int[length1 + length2];
|
||||
System.arraycopy(list1, 0, combinedArray, 0, list1.length);
|
||||
System.arraycopy(list2, 0, combinedArray, list1.length, list2.length);
|
||||
Arrays.sort(combinedArray);
|
||||
|
||||
return combinedArray[k-1];
|
||||
}
|
||||
|
||||
public static int getKthElementMerge(int[] list1, int[] list2, int k) {
|
||||
|
||||
int i1 = 0, i2 = 0;
|
||||
|
||||
while(i1 < list1.length && i2 < list2.length && (i1 + i2) < k) {
|
||||
if(list1[i1] < list2[i2]) {
|
||||
i1++;
|
||||
} else {
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
|
||||
if((i1 + i2) < k) {
|
||||
return i1 < list1.length ? list1[k - i2 - 1] : list2[k - i1 - 1];
|
||||
} else if(i1 > 0 && i2 > 0) {
|
||||
return Math.max(list1[i1-1], list2[i2-1]);
|
||||
} else {
|
||||
return i1 == 0 ? list2[i2-1] : list1[i1-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.baeldung.algorithms.mcts.montecarlo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tree.Node;
|
||||
import com.baeldung.algorithms.mcts.tree.Tree;
|
||||
|
||||
public class MonteCarloTreeSearch {
|
||||
|
||||
private static final int WIN_SCORE = 10;
|
||||
private int level;
|
||||
private int opponent;
|
||||
|
||||
public MonteCarloTreeSearch() {
|
||||
this.level = 3;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
private int getMillisForCurrentLevel() {
|
||||
return 2 * (this.level - 1) + 1;
|
||||
}
|
||||
|
||||
public Board findNextMove(Board board, int playerNo) {
|
||||
long start = System.currentTimeMillis();
|
||||
long end = start + 60 * getMillisForCurrentLevel();
|
||||
|
||||
opponent = 3 - playerNo;
|
||||
Tree tree = new Tree();
|
||||
Node rootNode = tree.getRoot();
|
||||
rootNode.getState().setBoard(board);
|
||||
rootNode.getState().setPlayerNo(opponent);
|
||||
|
||||
while (System.currentTimeMillis() < end) {
|
||||
// Phase 1 - Selection
|
||||
Node promisingNode = selectPromisingNode(rootNode);
|
||||
// Phase 2 - Expansion
|
||||
if (promisingNode.getState().getBoard().checkStatus() == Board.IN_PROGRESS)
|
||||
expandNode(promisingNode);
|
||||
|
||||
// Phase 3 - Simulation
|
||||
Node nodeToExplore = promisingNode;
|
||||
if (promisingNode.getChildArray().size() > 0) {
|
||||
nodeToExplore = promisingNode.getRandomChildNode();
|
||||
}
|
||||
int playoutResult = simulateRandomPlayout(nodeToExplore);
|
||||
// Phase 4 - Update
|
||||
backPropogation(nodeToExplore, playoutResult);
|
||||
}
|
||||
|
||||
Node winnerNode = rootNode.getChildWithMaxScore();
|
||||
tree.setRoot(winnerNode);
|
||||
return winnerNode.getState().getBoard();
|
||||
}
|
||||
|
||||
private Node selectPromisingNode(Node rootNode) {
|
||||
Node node = rootNode;
|
||||
while (node.getChildArray().size() != 0) {
|
||||
node = UCT.findBestNodeWithUCT(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private void expandNode(Node node) {
|
||||
List<State> possibleStates = node.getState().getAllPossibleStates();
|
||||
possibleStates.forEach(state -> {
|
||||
Node newNode = new Node(state);
|
||||
newNode.setParent(node);
|
||||
newNode.getState().setPlayerNo(node.getState().getOpponent());
|
||||
node.getChildArray().add(newNode);
|
||||
});
|
||||
}
|
||||
|
||||
private void backPropogation(Node nodeToExplore, int playerNo) {
|
||||
Node tempNode = nodeToExplore;
|
||||
while (tempNode != null) {
|
||||
tempNode.getState().incrementVisit();
|
||||
if (tempNode.getState().getPlayerNo() == playerNo)
|
||||
tempNode.getState().addScore(WIN_SCORE);
|
||||
tempNode = tempNode.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
private int simulateRandomPlayout(Node node) {
|
||||
Node tempNode = new Node(node);
|
||||
State tempState = tempNode.getState();
|
||||
int boardStatus = tempState.getBoard().checkStatus();
|
||||
|
||||
if (boardStatus == opponent) {
|
||||
tempNode.getParent().getState().setWinScore(Integer.MIN_VALUE);
|
||||
return boardStatus;
|
||||
}
|
||||
while (boardStatus == Board.IN_PROGRESS) {
|
||||
tempState.togglePlayer();
|
||||
tempState.randomPlay();
|
||||
boardStatus = tempState.getBoard().checkStatus();
|
||||
}
|
||||
|
||||
return boardStatus;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.baeldung.algorithms.mcts.montecarlo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Position;
|
||||
|
||||
public class State {
|
||||
private Board board;
|
||||
private int playerNo;
|
||||
private int visitCount;
|
||||
private double winScore;
|
||||
|
||||
public State() {
|
||||
board = new Board();
|
||||
}
|
||||
|
||||
public State(State state) {
|
||||
this.board = new Board(state.getBoard());
|
||||
this.playerNo = state.getPlayerNo();
|
||||
this.visitCount = state.getVisitCount();
|
||||
this.winScore = state.getWinScore();
|
||||
}
|
||||
|
||||
public State(Board board) {
|
||||
this.board = new Board(board);
|
||||
}
|
||||
|
||||
Board getBoard() {
|
||||
return board;
|
||||
}
|
||||
|
||||
void setBoard(Board board) {
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
int getPlayerNo() {
|
||||
return playerNo;
|
||||
}
|
||||
|
||||
void setPlayerNo(int playerNo) {
|
||||
this.playerNo = playerNo;
|
||||
}
|
||||
|
||||
int getOpponent() {
|
||||
return 3 - playerNo;
|
||||
}
|
||||
|
||||
public int getVisitCount() {
|
||||
return visitCount;
|
||||
}
|
||||
|
||||
public void setVisitCount(int visitCount) {
|
||||
this.visitCount = visitCount;
|
||||
}
|
||||
|
||||
double getWinScore() {
|
||||
return winScore;
|
||||
}
|
||||
|
||||
void setWinScore(double winScore) {
|
||||
this.winScore = winScore;
|
||||
}
|
||||
|
||||
public List<State> getAllPossibleStates() {
|
||||
List<State> possibleStates = new ArrayList<>();
|
||||
List<Position> availablePositions = this.board.getEmptyPositions();
|
||||
availablePositions.forEach(p -> {
|
||||
State newState = new State(this.board);
|
||||
newState.setPlayerNo(3 - this.playerNo);
|
||||
newState.getBoard().performMove(newState.getPlayerNo(), p);
|
||||
possibleStates.add(newState);
|
||||
});
|
||||
return possibleStates;
|
||||
}
|
||||
|
||||
void incrementVisit() {
|
||||
this.visitCount++;
|
||||
}
|
||||
|
||||
void addScore(double score) {
|
||||
if (this.winScore != Integer.MIN_VALUE)
|
||||
this.winScore += score;
|
||||
}
|
||||
|
||||
void randomPlay() {
|
||||
List<Position> availablePositions = this.board.getEmptyPositions();
|
||||
int totalPossibilities = availablePositions.size();
|
||||
int selectRandom = (int) (Math.random() * totalPossibilities);
|
||||
this.board.performMove(this.playerNo, availablePositions.get(selectRandom));
|
||||
}
|
||||
|
||||
void togglePlayer() {
|
||||
this.playerNo = 3 - this.playerNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.algorithms.mcts.montecarlo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.tree.Node;
|
||||
|
||||
public class UCT {
|
||||
|
||||
public static double uctValue(int totalVisit, double nodeWinScore, int nodeVisit) {
|
||||
if (nodeVisit == 0) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return (nodeWinScore / (double) nodeVisit) + 1.41 * Math.sqrt(Math.log(totalVisit) / (double) nodeVisit);
|
||||
}
|
||||
|
||||
static Node findBestNodeWithUCT(Node node) {
|
||||
int parentVisit = node.getState().getVisitCount();
|
||||
return Collections.max(
|
||||
node.getChildArray(),
|
||||
Comparator.comparing(c -> uctValue(parentVisit, c.getState().getWinScore(), c.getState().getVisitCount())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.baeldung.algorithms.mcts.tictactoe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Board {
|
||||
int[][] boardValues;
|
||||
int totalMoves;
|
||||
|
||||
public static final int DEFAULT_BOARD_SIZE = 3;
|
||||
|
||||
public static final int IN_PROGRESS = -1;
|
||||
public static final int DRAW = 0;
|
||||
public static final int P1 = 1;
|
||||
public static final int P2 = 2;
|
||||
|
||||
public Board() {
|
||||
boardValues = new int[DEFAULT_BOARD_SIZE][DEFAULT_BOARD_SIZE];
|
||||
}
|
||||
|
||||
public Board(int boardSize) {
|
||||
boardValues = new int[boardSize][boardSize];
|
||||
}
|
||||
|
||||
public Board(int[][] boardValues) {
|
||||
this.boardValues = boardValues;
|
||||
}
|
||||
|
||||
public Board(int[][] boardValues, int totalMoves) {
|
||||
this.boardValues = boardValues;
|
||||
this.totalMoves = totalMoves;
|
||||
}
|
||||
|
||||
public Board(Board board) {
|
||||
int boardLength = board.getBoardValues().length;
|
||||
this.boardValues = new int[boardLength][boardLength];
|
||||
int[][] boardValues = board.getBoardValues();
|
||||
int n = boardValues.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int m = boardValues[i].length;
|
||||
for (int j = 0; j < m; j++) {
|
||||
this.boardValues[i][j] = boardValues[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void performMove(int player, Position p) {
|
||||
this.totalMoves++;
|
||||
boardValues[p.getX()][p.getY()] = player;
|
||||
}
|
||||
|
||||
public int[][] getBoardValues() {
|
||||
return boardValues;
|
||||
}
|
||||
|
||||
public void setBoardValues(int[][] boardValues) {
|
||||
this.boardValues = boardValues;
|
||||
}
|
||||
|
||||
public int checkStatus() {
|
||||
int boardSize = boardValues.length;
|
||||
int maxIndex = boardSize - 1;
|
||||
int[] diag1 = new int[boardSize];
|
||||
int[] diag2 = new int[boardSize];
|
||||
|
||||
for (int i = 0; i < boardSize; i++) {
|
||||
int[] row = boardValues[i];
|
||||
int[] col = new int[boardSize];
|
||||
for (int j = 0; j < boardSize; j++) {
|
||||
col[j] = boardValues[j][i];
|
||||
}
|
||||
|
||||
int checkRowForWin = checkForWin(row);
|
||||
if(checkRowForWin!=0)
|
||||
return checkRowForWin;
|
||||
|
||||
int checkColForWin = checkForWin(col);
|
||||
if(checkColForWin!=0)
|
||||
return checkColForWin;
|
||||
|
||||
diag1[i] = boardValues[i][i];
|
||||
diag2[i] = boardValues[maxIndex - i][i];
|
||||
}
|
||||
|
||||
int checkDia1gForWin = checkForWin(diag1);
|
||||
if(checkDia1gForWin!=0)
|
||||
return checkDia1gForWin;
|
||||
|
||||
int checkDiag2ForWin = checkForWin(diag2);
|
||||
if(checkDiag2ForWin!=0)
|
||||
return checkDiag2ForWin;
|
||||
|
||||
if (getEmptyPositions().size() > 0)
|
||||
return IN_PROGRESS;
|
||||
else
|
||||
return DRAW;
|
||||
}
|
||||
|
||||
private int checkForWin(int[] row) {
|
||||
boolean isEqual = true;
|
||||
int size = row.length;
|
||||
int previous = row[0];
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (previous != row[i]) {
|
||||
isEqual = false;
|
||||
break;
|
||||
}
|
||||
previous = row[i];
|
||||
}
|
||||
if(isEqual)
|
||||
return previous;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void printBoard() {
|
||||
int size = this.boardValues.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
System.out.print(boardValues[i][j] + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Position> getEmptyPositions() {
|
||||
int size = this.boardValues.length;
|
||||
List<Position> emptyPositions = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (boardValues[i][j] == 0)
|
||||
emptyPositions.add(new Position(i, j));
|
||||
}
|
||||
}
|
||||
return emptyPositions;
|
||||
}
|
||||
|
||||
public void printStatus() {
|
||||
switch (this.checkStatus()) {
|
||||
case P1:
|
||||
System.out.println("Player 1 wins");
|
||||
break;
|
||||
case P2:
|
||||
System.out.println("Player 2 wins");
|
||||
break;
|
||||
case DRAW:
|
||||
System.out.println("Game Draw");
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
System.out.println("Game In Progress");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.algorithms.mcts.tictactoe;
|
||||
|
||||
public class Position {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public Position() {
|
||||
}
|
||||
|
||||
public Position(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.baeldung.algorithms.mcts.tree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.baeldung.algorithms.mcts.montecarlo.State;
|
||||
|
||||
public class Node {
|
||||
State state;
|
||||
Node parent;
|
||||
List<Node> childArray;
|
||||
|
||||
public Node() {
|
||||
this.state = new State();
|
||||
childArray = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Node(State state) {
|
||||
this.state = state;
|
||||
childArray = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Node(State state, Node parent, List<Node> childArray) {
|
||||
this.state = state;
|
||||
this.parent = parent;
|
||||
this.childArray = childArray;
|
||||
}
|
||||
|
||||
public Node(Node node) {
|
||||
this.childArray = new ArrayList<>();
|
||||
this.state = new State(node.getState());
|
||||
if (node.getParent() != null)
|
||||
this.parent = node.getParent();
|
||||
List<Node> childArray = node.getChildArray();
|
||||
for (Node child : childArray) {
|
||||
this.childArray.add(new Node(child));
|
||||
}
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public Node getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Node parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public List<Node> getChildArray() {
|
||||
return childArray;
|
||||
}
|
||||
|
||||
public void setChildArray(List<Node> childArray) {
|
||||
this.childArray = childArray;
|
||||
}
|
||||
|
||||
public Node getRandomChildNode() {
|
||||
int noOfPossibleMoves = this.childArray.size();
|
||||
int selectRandom = (int) (Math.random() * noOfPossibleMoves);
|
||||
return this.childArray.get(selectRandom);
|
||||
}
|
||||
|
||||
public Node getChildWithMaxScore() {
|
||||
return Collections.max(this.childArray, Comparator.comparing(c -> {
|
||||
return c.getState().getVisitCount();
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.algorithms.mcts.tree;
|
||||
|
||||
public class Tree {
|
||||
Node root;
|
||||
|
||||
public Tree() {
|
||||
root = new Node();
|
||||
}
|
||||
|
||||
public Tree(Node root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public void setRoot(Node root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public void addChild(Node parent, Node child) {
|
||||
parent.getChildArray().add(child);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
public class Point {
|
||||
private float x;
|
||||
private float y;
|
||||
|
||||
public Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + x + " , " + y + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class QuadTree {
|
||||
private static final int MAX_POINTS = 3;
|
||||
private Region area;
|
||||
private List<Point> points = new ArrayList<>();
|
||||
private List<QuadTree> quadTrees = new ArrayList<>();
|
||||
private StringBuilder searchTraversePath;
|
||||
|
||||
public QuadTree(Region area) {
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
public boolean addPoint(Point point) {
|
||||
if (this.area.containsPoint(point)) {
|
||||
if (this.points.size() < MAX_POINTS) {
|
||||
this.points.add(point);
|
||||
return true;
|
||||
} else {
|
||||
if (this.quadTrees.size() == 0) {
|
||||
createQuadrants();
|
||||
}
|
||||
return addPointToOneQuadrant(point);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean addPointToOneQuadrant(Point point) {
|
||||
boolean isPointAdded;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
isPointAdded = this.quadTrees.get(i)
|
||||
.addPoint(point);
|
||||
if (isPointAdded)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createQuadrants() {
|
||||
Region region;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
region = this.area.getQuadrant(i);
|
||||
quadTrees.add(new QuadTree(region));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Point> search(Region searchRegion, List<Point> matches, String depthIndicator) {
|
||||
searchTraversePath = new StringBuilder();
|
||||
if (matches == null) {
|
||||
matches = new ArrayList<Point>();
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Search Boundary =")
|
||||
.append(searchRegion)
|
||||
.append("\n");
|
||||
}
|
||||
if (!this.area.doesOverlap(searchRegion)) {
|
||||
return matches;
|
||||
} else {
|
||||
for (Point point : points) {
|
||||
if (searchRegion.containsPoint(point)) {
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Found match " + point)
|
||||
.append("\n");
|
||||
matches.add(point);
|
||||
}
|
||||
}
|
||||
if (this.quadTrees.size() > 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
searchTraversePath.append(depthIndicator)
|
||||
.append("Q")
|
||||
.append(i)
|
||||
.append("-->")
|
||||
.append(quadTrees.get(i).area)
|
||||
.append("\n");
|
||||
quadTrees.get(i)
|
||||
.search(searchRegion, matches, depthIndicator + "\t");
|
||||
this.searchTraversePath.append(quadTrees.get(i)
|
||||
.printSearchTraversePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
public String printTree(String depthIndicator) {
|
||||
String str = "";
|
||||
if (depthIndicator == "") {
|
||||
str += "Root-->" + area.toString() + "\n";
|
||||
}
|
||||
|
||||
for (Point point : points) {
|
||||
str += depthIndicator + point.toString() + "\n";
|
||||
}
|
||||
for (int i = 0; i < quadTrees.size(); i++) {
|
||||
str += depthIndicator + "Q" + String.valueOf(i) + "-->" + quadTrees.get(i).area.toString() + "\n";
|
||||
str += quadTrees.get(i)
|
||||
.printTree(depthIndicator + "\t");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String printSearchTraversePath() {
|
||||
return searchTraversePath.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
public class Region {
|
||||
private float x1;
|
||||
private float y1;
|
||||
private float x2;
|
||||
private float y2;
|
||||
|
||||
public Region(float x1, float y1, float x2, float y2) {
|
||||
if (x1 >= x2 || y1 >= y2)
|
||||
throw new IllegalArgumentException("(x1,y1) should be lesser than (x2,y2)");
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
public Region getQuadrant(int quadrantIndex) {
|
||||
float quadrantWidth = (this.x2 - this.x1) / 2;
|
||||
float quadrantHeight = (this.y2 - this.y1) / 2;
|
||||
|
||||
// 0=SW, 1=NW, 2=NE, 3=SE
|
||||
switch (quadrantIndex) {
|
||||
case 0:
|
||||
return new Region(x1, y1, x1 + quadrantWidth, y1 + quadrantHeight);
|
||||
case 1:
|
||||
return new Region(x1, y1 + quadrantHeight, x1 + quadrantWidth, y2);
|
||||
case 2:
|
||||
return new Region(x1 + quadrantWidth, y1 + quadrantHeight, x2, y2);
|
||||
case 3:
|
||||
return new Region(x1 + quadrantWidth, y1, x2, y1 + quadrantHeight);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean containsPoint(Point point) {
|
||||
// Consider left and top side to be inclusive for points on border
|
||||
return point.getX() >= this.x1
|
||||
&& point.getX() < this.x2
|
||||
&& point.getY() >= this.y1
|
||||
&& point.getY() < this.y2;
|
||||
}
|
||||
|
||||
public boolean doesOverlap(Region testRegion) {
|
||||
// Is test region completely to left of my region?
|
||||
if (testRegion.getX2() < this.getX1()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely to right of my region?
|
||||
if (testRegion.getX1() > this.getX2()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely above my region?
|
||||
if (testRegion.getY1() > this.getY2()) {
|
||||
return false;
|
||||
}
|
||||
// Is test region completely below my region?
|
||||
if (testRegion.getY2() < this.getY1()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Region (x1=" + x1 + ", y1=" + y1 + "), (x2=" + x2 + ", y2=" + y2 + ")]";
|
||||
}
|
||||
|
||||
public float getX1() {
|
||||
return x1;
|
||||
}
|
||||
|
||||
public float getY1() {
|
||||
return y1;
|
||||
}
|
||||
|
||||
public float getX2() {
|
||||
return x2;
|
||||
}
|
||||
|
||||
public float getY2() {
|
||||
return y2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.baeldung.algorithms.suffixtree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Node {
|
||||
private String text;
|
||||
private List<Node> children;
|
||||
private int position;
|
||||
|
||||
public Node(String word, int position) {
|
||||
this.text = word;
|
||||
this.position = position;
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public List<Node> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(List<Node> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public String printTree(String depthIndicator) {
|
||||
String str = "";
|
||||
String positionStr = position > -1 ? "[" + String.valueOf(position) + "]" : "";
|
||||
str += depthIndicator + text + positionStr + "\n";
|
||||
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
str += children.get(i)
|
||||
.printTree(depthIndicator + "\t");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return printTree("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package com.baeldung.algorithms.suffixtree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SuffixTree {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SuffixTree.class);
|
||||
|
||||
private static final String WORD_TERMINATION = "$";
|
||||
private static final int POSITION_UNDEFINED = -1;
|
||||
private Node root;
|
||||
private String fullText;
|
||||
|
||||
public SuffixTree(String text) {
|
||||
root = new Node("", POSITION_UNDEFINED);
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
addSuffix(text.substring(i) + WORD_TERMINATION, i);
|
||||
}
|
||||
fullText = text;
|
||||
}
|
||||
|
||||
public List<String> searchText(String pattern) {
|
||||
LOGGER.debug("Searching for pattern \"{}\"", pattern);
|
||||
List<String> result = new ArrayList<>();
|
||||
List<Node> nodes = getAllNodesInTraversePath(pattern, root, false);
|
||||
|
||||
if (nodes.size() > 0) {
|
||||
Node lastNode = nodes.get(nodes.size() - 1);
|
||||
if (lastNode != null) {
|
||||
List<Integer> positions = getPositions(lastNode);
|
||||
positions = positions.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
positions.forEach(m -> result.add((markPatternInText(m, pattern))));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addSuffix(String suffix, int position) {
|
||||
LOGGER.debug(">>>>>>>>>>>> Adding new suffix {}", suffix);
|
||||
List<Node> nodes = getAllNodesInTraversePath(suffix, root, true);
|
||||
if (nodes.size() == 0) {
|
||||
addChildNode(root, suffix, position);
|
||||
LOGGER.debug("{}", printTree());
|
||||
} else {
|
||||
Node lastNode = nodes.remove(nodes.size() - 1);
|
||||
String newText = suffix;
|
||||
if (nodes.size() > 0) {
|
||||
String existingSuffixUptoLastNode = nodes.stream()
|
||||
.map(a -> a.getText())
|
||||
.reduce("", String::concat);
|
||||
|
||||
// Remove prefix from newText already included in parent
|
||||
newText = newText.substring(existingSuffixUptoLastNode.length());
|
||||
}
|
||||
extendNode(lastNode, newText, position);
|
||||
LOGGER.debug("{}", printTree());
|
||||
}
|
||||
}
|
||||
|
||||
private List<Integer> getPositions(Node node) {
|
||||
List<Integer> positions = new ArrayList<>();
|
||||
if (node.getText()
|
||||
.endsWith(WORD_TERMINATION)) {
|
||||
positions.add(node.getPosition());
|
||||
}
|
||||
for (int i = 0; i < node.getChildren()
|
||||
.size(); i++) {
|
||||
positions.addAll(getPositions(node.getChildren()
|
||||
.get(i)));
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
private String markPatternInText(Integer startPosition, String pattern) {
|
||||
String matchingTextLHS = fullText.substring(0, startPosition);
|
||||
String matchingText = fullText.substring(startPosition, startPosition + pattern.length());
|
||||
String matchingTextRHS = fullText.substring(startPosition + pattern.length());
|
||||
return matchingTextLHS + "[" + matchingText + "]" + matchingTextRHS;
|
||||
}
|
||||
|
||||
private void addChildNode(Node parentNode, String text, int position) {
|
||||
parentNode.getChildren()
|
||||
.add(new Node(text, position));
|
||||
}
|
||||
|
||||
private void extendNode(Node node, String newText, int position) {
|
||||
String currentText = node.getText();
|
||||
String commonPrefix = getLongestCommonPrefix(currentText, newText);
|
||||
|
||||
if (commonPrefix != currentText) {
|
||||
String parentText = currentText.substring(0, commonPrefix.length());
|
||||
String childText = currentText.substring(commonPrefix.length());
|
||||
splitNodeToParentAndChild(node, parentText, childText);
|
||||
}
|
||||
|
||||
String remainingText = newText.substring(commonPrefix.length());
|
||||
addChildNode(node, remainingText, position);
|
||||
}
|
||||
|
||||
private void splitNodeToParentAndChild(Node parentNode, String parentNewText, String childNewText) {
|
||||
Node childNode = new Node(childNewText, parentNode.getPosition());
|
||||
|
||||
if (parentNode.getChildren()
|
||||
.size() > 0) {
|
||||
while (parentNode.getChildren()
|
||||
.size() > 0) {
|
||||
childNode.getChildren()
|
||||
.add(parentNode.getChildren()
|
||||
.remove(0));
|
||||
}
|
||||
}
|
||||
|
||||
parentNode.getChildren()
|
||||
.add(childNode);
|
||||
parentNode.setText(parentNewText);
|
||||
parentNode.setPosition(POSITION_UNDEFINED);
|
||||
}
|
||||
|
||||
private String getLongestCommonPrefix(String str1, String str2) {
|
||||
int compareLength = Math.min(str1.length(), str2.length());
|
||||
for (int i = 0; i < compareLength; i++) {
|
||||
if (str1.charAt(i) != str2.charAt(i)) {
|
||||
return str1.substring(0, i);
|
||||
}
|
||||
}
|
||||
return str1.substring(0, compareLength);
|
||||
}
|
||||
|
||||
private List<Node> getAllNodesInTraversePath(String pattern, Node startNode, boolean isAllowPartialMatch) {
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
for (int i = 0; i < startNode.getChildren()
|
||||
.size(); i++) {
|
||||
Node currentNode = startNode.getChildren()
|
||||
.get(i);
|
||||
String nodeText = currentNode.getText();
|
||||
if (pattern.charAt(0) == nodeText.charAt(0)) {
|
||||
if (isAllowPartialMatch && pattern.length() <= nodeText.length()) {
|
||||
nodes.add(currentNode);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
int compareLength = Math.min(nodeText.length(), pattern.length());
|
||||
for (int j = 1; j < compareLength; j++) {
|
||||
if (pattern.charAt(j) != nodeText.charAt(j)) {
|
||||
if (isAllowPartialMatch) {
|
||||
nodes.add(currentNode);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
nodes.add(currentNode);
|
||||
if (pattern.length() > compareLength) {
|
||||
List<Node> nodes2 = getAllNodesInTraversePath(pattern.substring(compareLength), currentNode, isAllowPartialMatch);
|
||||
if (nodes2.size() > 0) {
|
||||
nodes.addAll(nodes2);
|
||||
} else if (!isAllowPartialMatch) {
|
||||
nodes.add(null);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public String printTree() {
|
||||
return root.printTree("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.baeldung.algorithms.textsearch;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
public class TextSearchAlgorithms {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.baeldung.algorithms.binarysearch;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BinarySearchUnitTest {
|
||||
|
||||
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<Integer> 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.baeldung.algorithms.breadthfirstsearch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class BreadthFirstSearchAlgorithmUnitTest {
|
||||
|
||||
private Tree<Integer> root;
|
||||
private Tree<Integer> rootFirstChild;
|
||||
private Tree<Integer> depthMostChild;
|
||||
private Tree<Integer> rootSecondChild;
|
||||
|
||||
private Node<Integer> start;
|
||||
private Node<Integer> firstNeighbor;
|
||||
private Node<Integer> firstNeighborNeighbor;
|
||||
private Node<Integer> secondNeighbor;
|
||||
|
||||
@Test
|
||||
void givenTree_whenSearchTen_thenRoot() {
|
||||
initTree();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(10, root)).isPresent().contains(root);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTree_whenSearchThree_thenDepthMostValue() {
|
||||
initTree();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(3, root)).isPresent().contains(depthMostChild);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTree_whenSearchFour_thenRootSecondChild() {
|
||||
initTree();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(4, root)).isPresent().contains(rootSecondChild);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTree_whenSearchFive_thenNotFound() {
|
||||
initTree();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(5, root)).isEmpty();
|
||||
}
|
||||
|
||||
private void initTree() {
|
||||
root = Tree.of(10);
|
||||
rootFirstChild = root.addChild(2);
|
||||
depthMostChild = rootFirstChild.addChild(3);
|
||||
rootSecondChild = root.addChild(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNode_whenSearchTen_thenStart() {
|
||||
initNode();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(10, firstNeighborNeighbor)).isPresent().contains(start);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNode_whenSearchThree_thenNeighborNeighbor() {
|
||||
initNode();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(3, firstNeighborNeighbor)).isPresent().contains(firstNeighborNeighbor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNode_whenSearchFour_thenSecondNeighbor() {
|
||||
initNode();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(4, firstNeighborNeighbor)).isPresent().contains(secondNeighbor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNode_whenSearchFive_thenNotFound() {
|
||||
initNode();
|
||||
assertThat(BreadthFirstSearchAlgorithm.search(5, firstNeighborNeighbor)).isEmpty();
|
||||
}
|
||||
|
||||
private void initNode() {
|
||||
start = new Node<>(10);
|
||||
firstNeighbor = new Node<>(2);
|
||||
start.connect(firstNeighbor);
|
||||
|
||||
firstNeighborNeighbor = new Node<>(3);
|
||||
firstNeighbor.connect(firstNeighborNeighbor);
|
||||
firstNeighborNeighbor.connect(start);
|
||||
|
||||
secondNeighbor = new Node<>(4);
|
||||
start.connect(secondNeighbor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.baeldung.algorithms.dfs;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BinaryTreeUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenAddingElements_ThenTreeNotEmpty() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
assertFalse(bt.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenAddingElements_ThenTreeContainsThoseElements() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
assertTrue(bt.containsNode(6));
|
||||
assertTrue(bt.containsNode(4));
|
||||
|
||||
assertFalse(bt.containsNode(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenAddingExistingElement_ThenElementIsNotAdded() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
int initialSize = bt.getSize();
|
||||
|
||||
assertTrue(bt.containsNode(3));
|
||||
bt.add(3);
|
||||
assertEquals(initialSize, bt.getSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenLookingForNonExistingElement_ThenReturnsFalse() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
assertFalse(bt.containsNode(99));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
assertTrue(bt.containsNode(9));
|
||||
bt.delete(9);
|
||||
assertFalse(bt.containsNode(9));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenDeletingNonExistingElement_ThenTreeDoesNotDelete() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
int initialSize = bt.getSize();
|
||||
|
||||
assertFalse(bt.containsNode(99));
|
||||
bt.delete(99);
|
||||
assertFalse(bt.containsNode(99));
|
||||
assertEquals(initialSize, bt.getSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void it_deletes_the_root() {
|
||||
int value = 12;
|
||||
BinaryTree bt = new BinaryTree();
|
||||
bt.add(value);
|
||||
|
||||
assertTrue(bt.containsNode(value));
|
||||
bt.delete(value);
|
||||
assertFalse(bt.containsNode(value));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
bt.traverseInOrder(bt.root);
|
||||
System.out.println();
|
||||
bt.traverseInOrderWithoutRecursion();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenTraversingPreOrder_ThenPrintValues() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
bt.traversePreOrder(bt.root);
|
||||
System.out.println();
|
||||
bt.traversePreOrderWithoutRecursion();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenABinaryTree_WhenTraversingPostOrder_ThenPrintValues() {
|
||||
|
||||
BinaryTree bt = createBinaryTree();
|
||||
|
||||
bt.traversePostOrder(bt.root);
|
||||
System.out.println();
|
||||
bt.traversePostOrderWithoutRecursion();
|
||||
}
|
||||
|
||||
private BinaryTree createBinaryTree() {
|
||||
BinaryTree bt = new BinaryTree();
|
||||
|
||||
bt.add(6);
|
||||
bt.add(4);
|
||||
bt.add(8);
|
||||
bt.add(3);
|
||||
bt.add(5);
|
||||
bt.add(7);
|
||||
bt.add(9);
|
||||
|
||||
return bt;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.baeldung.algorithms.dfs;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class GraphUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenDFS_thenPrintAllValues() {
|
||||
Graph graph = createDirectedGraph();
|
||||
graph.dfs(0);
|
||||
System.out.println();
|
||||
graph.dfsWithoutRecursion(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenGetTopologicalSort_thenPrintValuesSorted() {
|
||||
Graph graph = createDirectedGraph();
|
||||
List<Integer> list = graph.topologicalSort(0);
|
||||
System.out.println(list);
|
||||
}
|
||||
|
||||
private Graph createDirectedGraph() {
|
||||
Graph graph = new Graph();
|
||||
graph.addVertex(0);
|
||||
graph.addVertex(1);
|
||||
graph.addVertex(2);
|
||||
graph.addVertex(3);
|
||||
graph.addVertex(4);
|
||||
graph.addVertex(5);
|
||||
graph.addEdge(0, 1);
|
||||
graph.addEdge(0, 2);
|
||||
graph.addEdge(1, 3);
|
||||
graph.addEdge(2, 3);
|
||||
graph.addEdge(3, 4);
|
||||
graph.addEdge(4, 5);
|
||||
return graph;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.algorithms.interpolationsearch;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class InterpolationSearchUnitTest {
|
||||
|
||||
private int[] myData;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
myData = new int[]{13,21,34,55,69,73,84,101};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSortedArray_whenLookingFor84_thenReturn6() {
|
||||
int pos = InterpolationSearch.interpolationSearch(myData, 84);
|
||||
assertEquals(6, pos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSortedArray_whenLookingFor19_thenReturnMinusOne() {
|
||||
int pos = InterpolationSearch.interpolationSearch(myData, 19);
|
||||
assertEquals(-1, pos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package com.baeldung.algorithms.kthsmallest;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.baeldung.algorithms.kthsmallest.KthSmallest.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class KthSmallestUnitTest {
|
||||
|
||||
@Nested
|
||||
class Exceptions {
|
||||
|
||||
@Test
|
||||
public void when_at_least_one_list_is_null_then_an_exception_is_thrown() {
|
||||
|
||||
Executable executable1 = () -> findKthSmallestElement(1, null, null);
|
||||
Executable executable2 = () -> findKthSmallestElement(1, new int[]{2}, null);
|
||||
Executable executable3 = () -> findKthSmallestElement(1, null, new int[]{2});
|
||||
|
||||
assertThrows(IllegalArgumentException.class, executable1);
|
||||
assertThrows(IllegalArgumentException.class, executable2);
|
||||
assertThrows(IllegalArgumentException.class, executable3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_at_least_one_list_is_empty_then_an_exception_is_thrown() {
|
||||
|
||||
Executable executable1 = () -> findKthSmallestElement(1, new int[]{}, new int[]{2});
|
||||
Executable executable2 = () -> findKthSmallestElement(1, new int[]{2}, new int[]{});
|
||||
Executable executable3 = () -> findKthSmallestElement(1, new int[]{}, new int[]{});
|
||||
|
||||
assertThrows(IllegalArgumentException.class, executable1);
|
||||
assertThrows(IllegalArgumentException.class, executable2);
|
||||
assertThrows(IllegalArgumentException.class, executable3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_smaller_than_0_then_an_exception_is_thrown() {
|
||||
Executable executable1 = () -> findKthSmallestElement(-1, new int[]{2}, new int[]{2});
|
||||
assertThrows(IllegalArgumentException.class, executable1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_smaller_than_1_then_an_exception_is_thrown() {
|
||||
Executable executable1 = () -> findKthSmallestElement(0, new int[]{2}, new int[]{2});
|
||||
assertThrows(IllegalArgumentException.class, executable1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_bigger_then_the_two_lists_then_an_exception_is_thrown() {
|
||||
Executable executable1 = () -> findKthSmallestElement(6, new int[]{1, 5, 6}, new int[]{2, 5});
|
||||
assertThrows(NoSuchElementException.class, executable1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class K_is_smaller_than_the_size_of_list1_and_the_size_of_list2 {
|
||||
|
||||
@Test
|
||||
public void when_k_is_1_then_the_smallest_element_is_returned_from_list1() {
|
||||
int result = findKthSmallestElement(1, new int[]{2, 7}, new int[]{3, 5});
|
||||
assertEquals(2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_1_then_the_smallest_element_is_returned_list2() {
|
||||
int result = findKthSmallestElement(1, new int[]{3, 5}, new int[]{2, 7});
|
||||
assertEquals(2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_kth_element_is_smallest_element_and_occurs_in_both_lists() {
|
||||
int[] list1 = new int[]{1, 2, 3};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(1, list1, list2);
|
||||
assertEquals(1, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_kth_element_is_smallest_element_and_occurs_in_both_lists2() {
|
||||
int[] list1 = new int[]{1, 2, 3};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(2, list1, list2);
|
||||
assertEquals(1, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_kth_element_is_largest_element_and_occurs_in_both_lists_1() {
|
||||
int[] list1 = new int[]{1, 2, 3};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(5, list1, list2);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_kth_element_is_largest_element_and_occurs_in_both_lists_2() {
|
||||
int[] list1 = new int[]{1, 2, 3};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(6, list1, list2);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_kth_element_and_occurs_in_both_lists() {
|
||||
int[] list1 = new int[]{1, 2, 3};
|
||||
int[] list2 = new int[]{0, 2, 3};
|
||||
int result = findKthSmallestElement(3, list1, list2);
|
||||
assertEquals(2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and_kth_element_is_in_first_list() {
|
||||
int[] list1 = new int[]{1,2,3,4};
|
||||
int[] list2 = new int[]{1,3,4,5};
|
||||
int result = findKthSmallestElement(3, list1, list2);
|
||||
assertEquals(2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and_kth_is_in_second_list() {
|
||||
int[] list1 = new int[]{1,3,4,4};
|
||||
int[] list2 = new int[]{1,2,4,5};
|
||||
int result = findKthSmallestElement(3, list1, list2);
|
||||
assertEquals(2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and_elements_in_first_list_are_all_smaller_than_second_list() {
|
||||
int[] list1 = new int[]{1,3,7,9};
|
||||
int[] list2 = new int[]{11,12,14,15};
|
||||
int result = findKthSmallestElement(3, list1, list2);
|
||||
assertEquals(7, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and_elements_in_first_list_are_all_smaller_than_second_list2() {
|
||||
int[] list1 = new int[]{1,3,7,9};
|
||||
int[] list2 = new int[]{11,12,14,15};
|
||||
int result = findKthSmallestElement(4, list1, list2);
|
||||
assertEquals(9, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and_only_elements_from_second_list_are_part_of_result() {
|
||||
int[] list1 = new int[]{11,12,14,15};
|
||||
int[] list2 = new int[]{1,3,7,9};
|
||||
int result = findKthSmallestElement(3, list1, list2);
|
||||
assertEquals(7, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and_only_elements_from_second_list_are_part_of_result2() {
|
||||
int[] list1 = new int[]{11,12,14,15};
|
||||
int[] list2 = new int[]{1,3,7,9};
|
||||
int result = findKthSmallestElement(4, list1, list2);
|
||||
assertEquals(9, result);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class K_is_bigger_than_the_size_of_at_least_one_of_the_lists {
|
||||
|
||||
@Test
|
||||
public void k_is_smaller_than_list1_and_bigger_than_list2() {
|
||||
int[] list1 = new int[]{1, 2, 3, 4, 7, 9};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(5, list1, list2);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void k_is_bigger_than_list1_and_smaller_than_list2() {
|
||||
int[] list1 = new int[]{1, 2, 3};
|
||||
int[] list2 = new int[]{1, 2, 3, 4, 7, 9};
|
||||
int result = findKthSmallestElement(5, list1, list2);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_bigger_than_the_size_of_both_lists_and_elements_in_second_list_are_all_smaller_than_first_list() {
|
||||
int[] list1 = new int[]{9, 11, 13, 55};
|
||||
int[] list2 = new int[]{1, 2, 3, 7};
|
||||
int result = findKthSmallestElement(6, list1, list2);
|
||||
assertEquals(11, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_bigger_than_the_size_of_both_lists_and_elements_in_second_list_are_all_bigger_than_first_list() {
|
||||
int[] list1 = new int[]{1, 2, 3, 7};
|
||||
int[] list2 = new int[]{9, 11, 13, 55};
|
||||
int result = findKthSmallestElement(6, list1, list2);
|
||||
assertEquals(11, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_bigger_than_the_size_of_both_lists() {
|
||||
int[] list1 = new int[]{3, 7, 9, 11, 55};
|
||||
int[] list2 = new int[]{1, 2, 3, 7, 13};
|
||||
int result = findKthSmallestElement(7, list1, list2);
|
||||
assertEquals(9, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_bigger_than_the_size_of_both_lists_and_list1_has_more_elements_than_list2() {
|
||||
int[] list1 = new int[]{3, 7, 9, 11, 55, 77, 100, 200};
|
||||
int[] list2 = new int[]{1, 2, 3, 7, 13};
|
||||
int result = findKthSmallestElement(11, list1, list2);
|
||||
assertEquals(77, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void max_test() {
|
||||
int[] list1 = new int[]{100, 200};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(4, list1, list2);
|
||||
assertEquals(100, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void max_test2() {
|
||||
int[] list1 = new int[]{100, 200};
|
||||
int[] list2 = new int[]{1, 2, 3};
|
||||
int result = findKthSmallestElement(5, list1, list2);
|
||||
assertEquals(200, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_smaller_than_the_size_of_both_lists_and_kth_element_in_list2() {
|
||||
int[] list1 = new int[]{1, 2, 5};
|
||||
int[] list2 = new int[]{1, 3, 4, 7};
|
||||
int result = findKthSmallestElement(4, list1, list2);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_smaller_than_the_size_of_both_lists_and_kth_element_is_smallest_in_list2() {
|
||||
int[] list1 = new int[]{1, 2, 5};
|
||||
int[] list2 = new int[]{3, 4, 7};
|
||||
int result = findKthSmallestElement(3, list1, list2);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void when_k_is_smaller_than_the_size_of_both_lists_and_kth_element_is_smallest_in_list23() {
|
||||
int[] list1 = new int[]{3, 11, 27, 53, 90};
|
||||
int[] list2 = new int[]{4, 20, 21, 100};
|
||||
int result = findKthSmallestElement(5, list1, list2);
|
||||
assertEquals(21, result);
|
||||
}
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void randomTests() {
|
||||
// IntStream.range(1, 100000).forEach(i -> random());
|
||||
// }
|
||||
|
||||
private void random() {
|
||||
|
||||
Random random = new Random();
|
||||
int length1 = (Math.abs(random.nextInt())) % 1000 + 1;
|
||||
int length2 = (Math.abs(random.nextInt())) % 1000 + 1;
|
||||
|
||||
int[] list1 = sortedRandomIntArrayOfLength(length1);
|
||||
int[] list2 = sortedRandomIntArrayOfLength(length2);
|
||||
|
||||
int k = (Math.abs(random.nextInt()) % (length1 + length2)) + 1 ;
|
||||
|
||||
int result = findKthSmallestElement(k, list1, list2);
|
||||
|
||||
int result2 = getKthElementSorted(list1, list2, k);
|
||||
|
||||
int result3 = getKthElementMerge(list1, list2, k);
|
||||
|
||||
assertEquals(result2, result);
|
||||
assertEquals(result2, result3);
|
||||
}
|
||||
|
||||
private int[] sortedRandomIntArrayOfLength(int length) {
|
||||
int[] intArray = new Random().ints(length).toArray();
|
||||
Arrays.sort(intArray);
|
||||
return intArray;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.baeldung.algorithms.mcts;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch;
|
||||
import com.baeldung.algorithms.mcts.montecarlo.State;
|
||||
import com.baeldung.algorithms.mcts.montecarlo.UCT;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Board;
|
||||
import com.baeldung.algorithms.mcts.tictactoe.Position;
|
||||
import com.baeldung.algorithms.mcts.tree.Tree;
|
||||
|
||||
public class MCTSUnitTest {
|
||||
private Tree gameTree;
|
||||
private MonteCarloTreeSearch mcts;
|
||||
|
||||
@Before
|
||||
public void initGameTree() {
|
||||
gameTree = new Tree();
|
||||
mcts = new MonteCarloTreeSearch();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() {
|
||||
double uctValue = 15.79;
|
||||
assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() {
|
||||
State initState = gameTree.getRoot().getState();
|
||||
List<State> possibleStates = initState.getAllPossibleStates();
|
||||
assertTrue(possibleStates.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() {
|
||||
Board board = new Board();
|
||||
int initAvailablePositions = board.getEmptyPositions().size();
|
||||
board.performMove(Board.P1, new Position(1, 1));
|
||||
int availablePositions = board.getEmptyPositions().size();
|
||||
assertTrue(initAvailablePositions > availablePositions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {
|
||||
Board board = new Board();
|
||||
|
||||
int player = Board.P1;
|
||||
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
|
||||
for (int i = 0; i < totalMoves; i++) {
|
||||
board = mcts.findNextMove(board, player);
|
||||
if (board.checkStatus() != -1) {
|
||||
break;
|
||||
}
|
||||
player = 3 - player;
|
||||
}
|
||||
int winStatus = board.checkStatus();
|
||||
assertEquals(winStatus, Board.DRAW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() {
|
||||
Board board = new Board();
|
||||
MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch();
|
||||
mcts1.setLevel(1);
|
||||
MonteCarloTreeSearch mcts3 = new MonteCarloTreeSearch();
|
||||
mcts3.setLevel(3);
|
||||
|
||||
int player = Board.P1;
|
||||
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
|
||||
for (int i = 0; i < totalMoves; i++) {
|
||||
if (player == Board.P1)
|
||||
board = mcts3.findNextMove(board, player);
|
||||
else
|
||||
board = mcts1.findNextMove(board, player);
|
||||
|
||||
if (board.checkStatus() != -1) {
|
||||
break;
|
||||
}
|
||||
player = 3 - player;
|
||||
}
|
||||
int winStatus = board.checkStatus();
|
||||
assertTrue(winStatus == Board.DRAW || winStatus == Board.P1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.baeldung.algorithms.quadtree;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class QuadTreeSearchUnitTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(QuadTreeSearchUnitTest.class);
|
||||
|
||||
private static QuadTree quadTree;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
Region area = new Region(0, 0, 400, 400);
|
||||
quadTree = new QuadTree(area);
|
||||
|
||||
float[][] points = new float[][] { { 21, 25 }, { 55, 53 }, { 70, 318 }, { 98, 302 },
|
||||
{ 49, 229 }, { 135, 229 }, { 224, 292 }, { 206, 321 }, { 197, 258 }, { 245, 238 } };
|
||||
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
Point point = new Point(points[i][0], points[i][1]);
|
||||
quadTree.addPoint(point);
|
||||
}
|
||||
LOGGER.debug("\n" + quadTree.printTree(""));
|
||||
LOGGER.debug("==============================================");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenQuadTree_whenSearchingForRange_thenReturn1MatchingItem() {
|
||||
Region searchArea = new Region(200, 200, 250, 250);
|
||||
List<Point> result = quadTree.search(searchArea, null, "");
|
||||
|
||||
LOGGER.debug(result.toString());
|
||||
LOGGER.debug(quadTree.printSearchTraversePath());
|
||||
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertArrayEquals(new float[] { 245, 238 },
|
||||
new float[]{result.get(0).getX(), result.get(0).getY() }, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenQuadTree_whenSearchingForRange_thenReturn2MatchingItems() {
|
||||
Region searchArea = new Region(0, 0, 100, 100);
|
||||
List<Point> result = quadTree.search(searchArea, null, "");
|
||||
|
||||
LOGGER.debug(result.toString());
|
||||
LOGGER.debug(quadTree.printSearchTraversePath());
|
||||
|
||||
Assert.assertEquals(2, result.size());
|
||||
Assert.assertArrayEquals(new float[] { 21, 25 },
|
||||
new float[]{result.get(0).getX(), result.get(0).getY() }, 0);
|
||||
Assert.assertArrayEquals(new float[] { 55, 53 },
|
||||
new float[]{result.get(1).getX(), result.get(1).getY() }, 0);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.baeldung.algorithms.suffixtree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SuffixTreeUnitTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SuffixTreeUnitTest.class);
|
||||
|
||||
private static SuffixTree suffixTree;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
suffixTree = new SuffixTree("havanabanana");
|
||||
printTree();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSuffixTree_whenSearchingForA_thenReturn6Matches() {
|
||||
List<String> matches = suffixTree.searchText("a");
|
||||
matches.stream()
|
||||
.forEach(m -> LOGGER.debug(m));
|
||||
Assert.assertArrayEquals(new String[] { "h[a]vanabanana", "hav[a]nabanana", "havan[a]banana", "havanab[a]nana", "havanaban[a]na", "havanabanan[a]" }, matches.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSuffixTree_whenSearchingForNab_thenReturn1Match() {
|
||||
List<String> matches = suffixTree.searchText("nab");
|
||||
matches.stream()
|
||||
.forEach(m -> LOGGER.debug(m));
|
||||
Assert.assertArrayEquals(new String[] { "hava[nab]anana" }, matches.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSuffixTree_whenSearchingForNag_thenReturnNoMatches() {
|
||||
List<String> matches = suffixTree.searchText("nag");
|
||||
matches.stream()
|
||||
.forEach(m -> LOGGER.debug(m));
|
||||
Assert.assertArrayEquals(new String[] {}, matches.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSuffixTree_whenSearchingForBanana_thenReturn2Matches() {
|
||||
List<String> matches = suffixTree.searchText("ana");
|
||||
matches.stream()
|
||||
.forEach(m -> LOGGER.debug(m));
|
||||
Assert.assertArrayEquals(new String[] { "hav[ana]banana", "havanab[ana]na", "havanaban[ana]" }, matches.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSuffixTree_whenSearchingForNa_thenReturn4Matches() {
|
||||
List<String> matches = suffixTree.searchText("na");
|
||||
matches.stream()
|
||||
.forEach(m -> LOGGER.debug(m));
|
||||
Assert.assertArrayEquals(new String[] { "hava[na]banana", "havanaba[na]na", "havanabana[na]" }, matches.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSuffixTree_whenSearchingForX_thenReturnNoMatches() {
|
||||
List<String> matches = suffixTree.searchText("x");
|
||||
matches.stream()
|
||||
.forEach(m -> LOGGER.debug(m));
|
||||
Assert.assertArrayEquals(new String[] {}, matches.toArray());
|
||||
}
|
||||
|
||||
private static void printTree() {
|
||||
suffixTree.printTree();
|
||||
|
||||
LOGGER.debug("\n" + suffixTree.printTree());
|
||||
LOGGER.debug("==============================================");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.algorithms.textsearch;
|
||||
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TextSearchAlgorithmsUnitTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testStringSearchAlgorithms() {
|
||||
String text = "This is some nice text.";
|
||||
String pattern = "some";
|
||||
|
||||
int realPosition = text.indexOf(pattern);
|
||||
Assert.assertTrue(realPosition == TextSearchAlgorithms.simpleTextSearch(pattern.toCharArray(), text.toCharArray()));
|
||||
Assert.assertTrue(realPosition == TextSearchAlgorithms.RabinKarpMethod(pattern.toCharArray(), text.toCharArray()));
|
||||
Assert.assertTrue(realPosition == TextSearchAlgorithms.KnuthMorrisPrattSearch(pattern.toCharArray(), text.toCharArray()));
|
||||
Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSimpleSearch(pattern.toCharArray(), text.toCharArray()));
|
||||
Assert.assertTrue(realPosition == TextSearchAlgorithms.BoyerMooreHorspoolSearch(pattern.toCharArray(), text.toCharArray()));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user