JAVA-12097: renamed algorithms-module to algorithms-modules
This commit is contained in:
17
algorithms-modules/algorithms-miscellaneous-2/README.md
Normal file
17
algorithms-modules/algorithms-miscellaneous-2/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## Algorithms - Miscellaneous
|
||||
|
||||
This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](/../algorithms-sorting) and
|
||||
[genetic algorithms](/../algorithms-genetic), have their own dedicated modules.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Dijkstra Shortest Path Algorithm in Java](https://www.baeldung.com/java-dijkstra)
|
||||
- [Introduction to Cobertura](https://www.baeldung.com/cobertura)
|
||||
- [Test a Linked List for Cyclicity](https://www.baeldung.com/java-linked-list-cyclicity)
|
||||
- [Introduction to JGraphT](https://www.baeldung.com/jgrapht)
|
||||
- [A Maze Solver in Java](https://www.baeldung.com/java-solve-maze)
|
||||
- [Create a Sudoku Solver in Java](https://www.baeldung.com/java-sudoku)
|
||||
- [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words)
|
||||
- [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations)
|
||||
- [Implementing A* Pathfinding in Java](https://www.baeldung.com/java-a-star-pathfinding)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-1) [[next -->]](/algorithms-miscellaneous-3)
|
||||
79
algorithms-modules/algorithms-miscellaneous-2/pom.xml
Normal file
79
algorithms-modules/algorithms-miscellaneous-2/pom.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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-miscellaneous-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>algorithms-miscellaneous-2</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>algorithms-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math3</artifactId>
|
||||
<version>${commons-math3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>${commons-codec.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-core</artifactId>
|
||||
<version>${org.jgrapht.core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-ext</artifactId>
|
||||
<version>${org.jgrapht.ext.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.allegro.finance</groupId>
|
||||
<artifactId>tradukisto</artifactId>
|
||||
<version>${tradukisto.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${cobertura-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<instrumentation>
|
||||
<ignores>
|
||||
<ignore>com/baeldung/algorithms/dijkstra/*</ignore>
|
||||
</ignores>
|
||||
<excludes>
|
||||
<exclude>com/baeldung/algorithms/dijkstra/*</exclude>
|
||||
</excludes>
|
||||
</instrumentation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<properties>
|
||||
<commons-math3.version>3.6.1</commons-math3.version>
|
||||
<tradukisto.version>1.0.1</tradukisto.version>
|
||||
<org.jgrapht.core.version>1.0.1</org.jgrapht.core.version>
|
||||
<org.jgrapht.ext.version>1.0.1</org.jgrapht.ext.version>
|
||||
<commons-codec.version>1.11</commons-codec.version>
|
||||
<cobertura-maven-plugin.version>2.7</cobertura-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.baeldung.algorithms;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
import com.baeldung.algorithms.slope_one.SlopeOne;
|
||||
|
||||
public class RunAlgorithm {
|
||||
|
||||
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
|
||||
Scanner in = new Scanner(System.in);
|
||||
System.out.println("1 - Slope One");
|
||||
System.out.println("2 - Dijkstra");
|
||||
int decision = in.nextInt();
|
||||
switch (decision) {
|
||||
case 1:
|
||||
SlopeOne.slopeOne(3);
|
||||
break;
|
||||
case 2:
|
||||
System.out.println("Please run the DijkstraAlgorithmLongRunningUnitTest.");
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown option");
|
||||
break;
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EditDistanceBase {
|
||||
|
||||
static int costOfSubstitution(char a, char b) {
|
||||
return a == b ? 0 : 1;
|
||||
}
|
||||
|
||||
static int min(int... numbers) {
|
||||
return Arrays.stream(numbers)
|
||||
.min().orElse(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
public class EditDistanceDynamicProgramming extends EditDistanceBase {
|
||||
|
||||
static int calculate(String x, String y) {
|
||||
int[][] dp = new int[x.length() + 1][y.length() + 1];
|
||||
|
||||
for (int i = 0; i <= x.length(); i++) {
|
||||
for (int j = 0; j <= y.length(); j++) {
|
||||
if (i == 0)
|
||||
dp[i][j] = j;
|
||||
|
||||
else if (j == 0)
|
||||
dp[i][j] = i;
|
||||
|
||||
else {
|
||||
dp[i][j] = min(dp[i - 1][j - 1]
|
||||
+ costOfSubstitution(x.charAt(i - 1), y.charAt(j - 1)),
|
||||
dp[i - 1][j] + 1, dp[i][j - 1] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[x.length()][y.length()];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
public class EditDistanceRecursive extends EditDistanceBase {
|
||||
|
||||
static int calculate(String x, String y) {
|
||||
|
||||
if (x.isEmpty()) {
|
||||
return y.length();
|
||||
}
|
||||
|
||||
if (y.isEmpty()) {
|
||||
return x.length();
|
||||
}
|
||||
|
||||
int substitution = calculate(x.substring(1), y.substring(1)) + costOfSubstitution(x.charAt(0), y.charAt(0));
|
||||
int insertion = calculate(x, y.substring(1)) + 1;
|
||||
int deletion = calculate(x.substring(1), y) + 1;
|
||||
|
||||
return min(substitution, insertion, deletion);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.baeldung.algorithms.ga.dijkstra;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class Dijkstra {
|
||||
|
||||
public static Graph calculateShortestPathFromSource(Graph graph, Node source) {
|
||||
|
||||
source.setDistance(0);
|
||||
|
||||
Set<Node> settledNodes = new HashSet<>();
|
||||
Set<Node> unsettledNodes = new HashSet<>();
|
||||
unsettledNodes.add(source);
|
||||
|
||||
while (unsettledNodes.size() != 0) {
|
||||
Node currentNode = getLowestDistanceNode(unsettledNodes);
|
||||
unsettledNodes.remove(currentNode);
|
||||
for (Entry<Node, Integer> adjacencyPair : currentNode.getAdjacentNodes().entrySet()) {
|
||||
Node adjacentNode = adjacencyPair.getKey();
|
||||
Integer edgeWeigh = adjacencyPair.getValue();
|
||||
|
||||
if (!settledNodes.contains(adjacentNode)) {
|
||||
CalculateMinimumDistance(adjacentNode, edgeWeigh, currentNode);
|
||||
unsettledNodes.add(adjacentNode);
|
||||
}
|
||||
}
|
||||
settledNodes.add(currentNode);
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
private static void CalculateMinimumDistance(Node evaluationNode, Integer edgeWeigh, Node sourceNode) {
|
||||
Integer sourceDistance = sourceNode.getDistance();
|
||||
if (sourceDistance + edgeWeigh < evaluationNode.getDistance()) {
|
||||
evaluationNode.setDistance(sourceDistance + edgeWeigh);
|
||||
LinkedList<Node> shortestPath = new LinkedList<>(sourceNode.getShortestPath());
|
||||
shortestPath.add(sourceNode);
|
||||
evaluationNode.setShortestPath(shortestPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static Node getLowestDistanceNode(Set<Node> unsettledNodes) {
|
||||
Node lowestDistanceNode = null;
|
||||
int lowestDistance = Integer.MAX_VALUE;
|
||||
for (Node node : unsettledNodes) {
|
||||
int nodeDistance = node.getDistance();
|
||||
if (nodeDistance < lowestDistance) {
|
||||
lowestDistance = nodeDistance;
|
||||
lowestDistanceNode = node;
|
||||
}
|
||||
}
|
||||
return lowestDistanceNode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.algorithms.ga.dijkstra;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Graph {
|
||||
|
||||
private Set<Node> nodes = new HashSet<>();
|
||||
|
||||
public void addNode(Node nodeA) {
|
||||
nodes.add(nodeA);
|
||||
}
|
||||
|
||||
public Set<Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public void setNodes(Set<Node> nodes) {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.baeldung.algorithms.ga.dijkstra;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Node {
|
||||
|
||||
private String name;
|
||||
|
||||
private LinkedList<Node> shortestPath = new LinkedList<>();
|
||||
|
||||
private Integer distance = Integer.MAX_VALUE;
|
||||
|
||||
private Map<Node, Integer> adjacentNodes = new HashMap<>();
|
||||
|
||||
public Node(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void addDestination(Node destination, int distance) {
|
||||
adjacentNodes.put(destination, distance);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Map<Node, Integer> getAdjacentNodes() {
|
||||
return adjacentNodes;
|
||||
}
|
||||
|
||||
public void setAdjacentNodes(Map<Node, Integer> adjacentNodes) {
|
||||
this.adjacentNodes = adjacentNodes;
|
||||
}
|
||||
|
||||
public Integer getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
public void setDistance(Integer distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public List<Node> getShortestPath() {
|
||||
return shortestPath;
|
||||
}
|
||||
|
||||
public void setShortestPath(LinkedList<Node> shortestPath) {
|
||||
this.shortestPath = shortestPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleDetectionBruteForce {
|
||||
|
||||
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
|
||||
if (head == null) {
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
Node<T> it1 = head;
|
||||
int nodesTraversedByOuter = 0;
|
||||
while (it1 != null && it1.next != null) {
|
||||
it1 = it1.next;
|
||||
nodesTraversedByOuter++;
|
||||
|
||||
int x = nodesTraversedByOuter;
|
||||
Node<T> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleDetectionByFastAndSlowIterators {
|
||||
|
||||
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
|
||||
if (head == null) {
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
Node<T> slow = head;
|
||||
Node<T> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class CycleDetectionByHashing {
|
||||
|
||||
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
|
||||
if (head == null) {
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
Set<Node<T>> set = new HashSet<>();
|
||||
Node<T> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleDetectionResult<T> {
|
||||
boolean cycleExists;
|
||||
Node<T> node;
|
||||
|
||||
public CycleDetectionResult(boolean cycleExists, Node<T> node) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.node = node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleRemovalBruteForce {
|
||||
|
||||
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
|
||||
CycleDetectionResult<T> 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 <T> void removeCycle(Node<T> loopNodeParam, Node<T> head) {
|
||||
Node<T> it = head;
|
||||
|
||||
while (it != null) {
|
||||
if (isNodeReachableFromLoopNode(it, loopNodeParam)) {
|
||||
Node<T> loopStart = it;
|
||||
findEndNodeAndBreakCycle(loopStart);
|
||||
break;
|
||||
}
|
||||
it = it.next;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> boolean isNodeReachableFromLoopNode(Node<T> it, Node<T> loopNodeParam) {
|
||||
Node<T> loopNode = loopNodeParam;
|
||||
|
||||
do {
|
||||
if (it == loopNode) {
|
||||
return true;
|
||||
}
|
||||
loopNode = loopNode.next;
|
||||
} while (loopNode.next != loopNodeParam);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static <T> void findEndNodeAndBreakCycle(Node<T> loopStartParam) {
|
||||
Node<T> loopStart = loopStartParam;
|
||||
|
||||
while (loopStart.next != loopStartParam) {
|
||||
loopStart = loopStart.next;
|
||||
}
|
||||
|
||||
loopStart.next = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleRemovalByCountingLoopNodes {
|
||||
|
||||
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
|
||||
CycleDetectionResult<T> result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
|
||||
|
||||
if (result.cycleExists) {
|
||||
removeCycle(result.node, head);
|
||||
}
|
||||
|
||||
return result.cycleExists;
|
||||
}
|
||||
|
||||
private static <T> void removeCycle(Node<T> loopNodeParam, Node<T> head) {
|
||||
int cycleLength = calculateCycleLength(loopNodeParam);
|
||||
Node<T> cycleLengthAdvancedIterator = head;
|
||||
Node<T> 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 <T> int calculateCycleLength(Node<T> loopNodeParam) {
|
||||
Node<T> loopNode = loopNodeParam;
|
||||
int length = 1;
|
||||
|
||||
while (loopNode.next != loopNodeParam) {
|
||||
length++;
|
||||
loopNode = loopNode.next;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleRemovalWithoutCountingLoopNodes {
|
||||
|
||||
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
|
||||
CycleDetectionResult<T> result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
|
||||
|
||||
if (result.cycleExists) {
|
||||
removeCycle(result.node, head);
|
||||
}
|
||||
|
||||
return result.cycleExists;
|
||||
}
|
||||
|
||||
private static <T> void removeCycle(Node<T> meetingPointParam, Node<T> head) {
|
||||
Node<T> loopNode = meetingPointParam;
|
||||
Node<T> it = head;
|
||||
|
||||
while (loopNode.next != it.next) {
|
||||
it = it.next;
|
||||
loopNode = loopNode.next;
|
||||
}
|
||||
|
||||
loopNode.next = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class Node<T> {
|
||||
T data;
|
||||
Node<T> next;
|
||||
|
||||
public static <T> Node<T> createNewNode(T data, Node<T> next) {
|
||||
Node<T> node = new Node<T>();
|
||||
node.data = data;
|
||||
node.next = next;
|
||||
return node;
|
||||
}
|
||||
|
||||
public static <T> void traverseList(Node<T> root) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node<T> node = root;
|
||||
while (node != null) {
|
||||
System.out.println(node.data);
|
||||
node = node.next;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Node<T> getTail(Node<T> root) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Node<T> node = root;
|
||||
while (node.next != null) {
|
||||
node = node.next;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class BFSMazeSolver {
|
||||
private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
|
||||
|
||||
public List<Coordinate> solve(Maze maze) {
|
||||
LinkedList<Coordinate> nextToVisit = new LinkedList<>();
|
||||
Coordinate start = maze.getEntry();
|
||||
nextToVisit.add(start);
|
||||
|
||||
while (!nextToVisit.isEmpty()) {
|
||||
Coordinate cur = nextToVisit.remove();
|
||||
|
||||
if (!maze.isValidLocation(cur.getX(), cur.getY()) || maze.isExplored(cur.getX(), cur.getY())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (maze.isWall(cur.getX(), cur.getY())) {
|
||||
maze.setVisited(cur.getX(), cur.getY(), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (maze.isExit(cur.getX(), cur.getY())) {
|
||||
return backtrackPath(cur);
|
||||
}
|
||||
|
||||
for (int[] direction : DIRECTIONS) {
|
||||
Coordinate coordinate = new Coordinate(cur.getX() + direction[0], cur.getY() + direction[1], cur);
|
||||
nextToVisit.add(coordinate);
|
||||
maze.setVisited(cur.getX(), cur.getY(), true);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<Coordinate> backtrackPath(Coordinate cur) {
|
||||
List<Coordinate> path = new ArrayList<>();
|
||||
Coordinate iter = cur;
|
||||
|
||||
while (iter != null) {
|
||||
path.add(iter);
|
||||
iter = iter.parent;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
public class Coordinate {
|
||||
int x;
|
||||
int y;
|
||||
Coordinate parent;
|
||||
|
||||
public Coordinate(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
public Coordinate(int x, int y, Coordinate parent) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
Coordinate getParent() {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DFSMazeSolver {
|
||||
private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
|
||||
|
||||
public List<Coordinate> solve(Maze maze) {
|
||||
List<Coordinate> path = new ArrayList<>();
|
||||
if (explore(maze, maze.getEntry()
|
||||
.getX(),
|
||||
maze.getEntry()
|
||||
.getY(),
|
||||
path)) {
|
||||
return path;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private boolean explore(Maze maze, int row, int col, List<Coordinate> path) {
|
||||
if (!maze.isValidLocation(row, col) || maze.isWall(row, col) || maze.isExplored(row, col)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
path.add(new Coordinate(row, col));
|
||||
maze.setVisited(row, col, true);
|
||||
|
||||
if (maze.isExit(row, col)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int[] direction : DIRECTIONS) {
|
||||
Coordinate coordinate = getNextCoordinate(row, col, direction[0], direction[1]);
|
||||
if (explore(maze, coordinate.getX(), coordinate.getY(), path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
path.remove(path.size() - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
private Coordinate getNextCoordinate(int row, int col, int i, int j) {
|
||||
return new Coordinate(row + i, col + j);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Maze {
|
||||
private static final int ROAD = 0;
|
||||
private static final int WALL = 1;
|
||||
private static final int START = 2;
|
||||
private static final int EXIT = 3;
|
||||
private static final int PATH = 4;
|
||||
|
||||
private int[][] maze;
|
||||
private boolean[][] visited;
|
||||
private Coordinate start;
|
||||
private Coordinate end;
|
||||
|
||||
public Maze(File maze) throws FileNotFoundException {
|
||||
String fileText = "";
|
||||
try (Scanner input = new Scanner(maze)) {
|
||||
while (input.hasNextLine()) {
|
||||
fileText += input.nextLine() + "\n";
|
||||
}
|
||||
}
|
||||
initializeMaze(fileText);
|
||||
}
|
||||
|
||||
private void initializeMaze(String text) {
|
||||
if (text == null || (text = text.trim()).length() == 0) {
|
||||
throw new IllegalArgumentException("empty lines data");
|
||||
}
|
||||
|
||||
String[] lines = text.split("[\r]?\n");
|
||||
maze = new int[lines.length][lines[0].length()];
|
||||
visited = new boolean[lines.length][lines[0].length()];
|
||||
|
||||
for (int row = 0; row < getHeight(); row++) {
|
||||
if (lines[row].length() != getWidth()) {
|
||||
throw new IllegalArgumentException("line " + (row + 1) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ")");
|
||||
}
|
||||
|
||||
for (int col = 0; col < getWidth(); col++) {
|
||||
if (lines[row].charAt(col) == '#')
|
||||
maze[row][col] = WALL;
|
||||
else if (lines[row].charAt(col) == 'S') {
|
||||
maze[row][col] = START;
|
||||
start = new Coordinate(row, col);
|
||||
} else if (lines[row].charAt(col) == 'E') {
|
||||
maze[row][col] = EXIT;
|
||||
end = new Coordinate(row, col);
|
||||
} else
|
||||
maze[row][col] = ROAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return maze.length;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return maze[0].length;
|
||||
}
|
||||
|
||||
public Coordinate getEntry() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public Coordinate getExit() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public boolean isExit(int x, int y) {
|
||||
return x == end.getX() && y == end.getY();
|
||||
}
|
||||
|
||||
public boolean isStart(int x, int y) {
|
||||
return x == start.getX() && y == start.getY();
|
||||
}
|
||||
|
||||
public boolean isExplored(int row, int col) {
|
||||
return visited[row][col];
|
||||
}
|
||||
|
||||
public boolean isWall(int row, int col) {
|
||||
return maze[row][col] == WALL;
|
||||
}
|
||||
|
||||
public void setVisited(int row, int col, boolean value) {
|
||||
visited[row][col] = value;
|
||||
}
|
||||
|
||||
public boolean isValidLocation(int row, int col) {
|
||||
if (row < 0 || row >= getHeight() || col < 0 || col >= getWidth()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void printPath(List<Coordinate> path) {
|
||||
int[][] tempMaze = Arrays.stream(maze)
|
||||
.map(int[]::clone)
|
||||
.toArray(int[][]::new);
|
||||
for (Coordinate coordinate : path) {
|
||||
if (isStart(coordinate.getX(), coordinate.getY()) || isExit(coordinate.getX(), coordinate.getY())) {
|
||||
continue;
|
||||
}
|
||||
tempMaze[coordinate.getX()][coordinate.getY()] = PATH;
|
||||
}
|
||||
System.out.println(toString(tempMaze));
|
||||
}
|
||||
|
||||
public String toString(int[][] maze) {
|
||||
StringBuilder result = new StringBuilder(getWidth() * (getHeight() + 1));
|
||||
for (int row = 0; row < getHeight(); row++) {
|
||||
for (int col = 0; col < getWidth(); col++) {
|
||||
if (maze[row][col] == ROAD) {
|
||||
result.append(' ');
|
||||
} else if (maze[row][col] == WALL) {
|
||||
result.append('#');
|
||||
} else if (maze[row][col] == START) {
|
||||
result.append('S');
|
||||
} else if (maze[row][col] == EXIT) {
|
||||
result.append('E');
|
||||
} else {
|
||||
result.append('.');
|
||||
}
|
||||
}
|
||||
result.append('\n');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = 0; i < visited.length; i++)
|
||||
Arrays.fill(visited[i], false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class MazeDriver {
|
||||
public static void main(String[] args) throws Exception {
|
||||
File maze1 = new File("src/main/resources/maze/maze1.txt");
|
||||
File maze2 = new File("src/main/resources/maze/maze2.txt");
|
||||
|
||||
execute(maze1);
|
||||
execute(maze2);
|
||||
}
|
||||
|
||||
private static void execute(File file) throws Exception {
|
||||
Maze maze = new Maze(file);
|
||||
dfs(maze);
|
||||
bfs(maze);
|
||||
}
|
||||
|
||||
private static void bfs(Maze maze) {
|
||||
BFSMazeSolver bfs = new BFSMazeSolver();
|
||||
List<Coordinate> path = bfs.solve(maze);
|
||||
maze.printPath(path);
|
||||
maze.reset();
|
||||
}
|
||||
|
||||
private static void dfs(Maze maze) {
|
||||
DFSMazeSolver dfs = new DFSMazeSolver();
|
||||
List<Coordinate> path = dfs.solve(maze);
|
||||
maze.printPath(path);
|
||||
maze.reset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.baeldung.algorithms.numberwordconverter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import pl.allegro.finance.tradukisto.MoneyConverters;
|
||||
|
||||
public class NumberWordConverter {
|
||||
|
||||
public static final String INVALID_INPUT_GIVEN = "Invalid input given";
|
||||
|
||||
public static final String[] ones = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
|
||||
|
||||
public static final String[] tens = {
|
||||
"", // 0
|
||||
"", // 1
|
||||
"twenty", // 2
|
||||
"thirty", // 3
|
||||
"forty", // 4
|
||||
"fifty", // 5
|
||||
"sixty", // 6
|
||||
"seventy", // 7
|
||||
"eighty", // 8
|
||||
"ninety" // 9
|
||||
};
|
||||
|
||||
public static String getMoneyIntoWords(String input) {
|
||||
MoneyConverters converter = MoneyConverters.ENGLISH_BANKING_MONEY_VALUE;
|
||||
return converter.asWords(new BigDecimal(input));
|
||||
}
|
||||
|
||||
public static String getMoneyIntoWords(final double money) {
|
||||
long dollar = (long) money;
|
||||
long cents = Math.round((money - dollar) * 100);
|
||||
if (money == 0D) {
|
||||
return "";
|
||||
}
|
||||
if (money < 0) {
|
||||
return INVALID_INPUT_GIVEN;
|
||||
}
|
||||
String dollarPart = "";
|
||||
if (dollar > 0) {
|
||||
dollarPart = convert(dollar) + " dollar" + (dollar == 1 ? "" : "s");
|
||||
}
|
||||
String centsPart = "";
|
||||
if (cents > 0) {
|
||||
if (dollarPart.length() > 0) {
|
||||
centsPart = " and ";
|
||||
}
|
||||
centsPart += convert(cents) + " cent" + (cents == 1 ? "" : "s");
|
||||
}
|
||||
return dollarPart + centsPart;
|
||||
}
|
||||
|
||||
private static String convert(final long n) {
|
||||
if (n < 0) {
|
||||
return INVALID_INPUT_GIVEN;
|
||||
}
|
||||
if (n < 20) {
|
||||
return ones[(int) n];
|
||||
}
|
||||
if (n < 100) {
|
||||
return tens[(int) n / 10] + ((n % 10 != 0) ? " " : "") + ones[(int) n % 10];
|
||||
}
|
||||
if (n < 1000) {
|
||||
return ones[(int) n / 100] + " hundred" + ((n % 100 != 0) ? " " : "") + convert(n % 100);
|
||||
}
|
||||
if (n < 1_000_000) {
|
||||
return convert(n / 1000) + " thousand" + ((n % 1000 != 0) ? " " : "") + convert(n % 1000);
|
||||
}
|
||||
if (n < 1_000_000_000) {
|
||||
return convert(n / 1_000_000) + " million" + ((n % 1_000_000 != 0) ? " " : "") + convert(n % 1_000_000);
|
||||
}
|
||||
return convert(n / 1_000_000_000) + " billion" + ((n % 1_000_000_000 != 0) ? " " : "") + convert(n % 1_000_000_000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.baeldung.algorithms.slope_one;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class InputData {
|
||||
|
||||
protected static List<Item> items = Arrays.asList(new Item("Candy"), new Item("Drink"), new Item("Soda"), new Item("Popcorn"), new Item("Snacks"));
|
||||
|
||||
public static Map<User, HashMap<Item, Double>> initializeData(int numberOfUsers) {
|
||||
Map<User, HashMap<Item, Double>> data = new HashMap<>();
|
||||
HashMap<Item, Double> newUser;
|
||||
Set<Item> newRecommendationSet;
|
||||
for (int i = 0; i < numberOfUsers; i++) {
|
||||
newUser = new HashMap<Item, Double>();
|
||||
newRecommendationSet = new HashSet<>();
|
||||
for (int j = 0; j < 3; j++) {
|
||||
newRecommendationSet.add(items.get((int) (Math.random() * 5)));
|
||||
}
|
||||
for (Item item : newRecommendationSet) {
|
||||
newUser.put(item, Math.random());
|
||||
}
|
||||
data.put(new User("User " + i), newUser);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.algorithms.slope_one;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Item {
|
||||
|
||||
private String itemName;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.baeldung.algorithms.slope_one;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Slope One algorithm implementation
|
||||
*/
|
||||
public class SlopeOne {
|
||||
|
||||
private static Map<Item, Map<Item, Double>> diff = new HashMap<>();
|
||||
private static Map<Item, Map<Item, Integer>> freq = new HashMap<>();
|
||||
private static Map<User, HashMap<Item, Double>> inputData;
|
||||
private static Map<User, HashMap<Item, Double>> outputData = new HashMap<>();
|
||||
|
||||
public static void slopeOne(int numberOfUsers) {
|
||||
inputData = InputData.initializeData(numberOfUsers);
|
||||
System.out.println("Slope One - Before the Prediction\n");
|
||||
buildDifferencesMatrix(inputData);
|
||||
System.out.println("\nSlope One - With Predictions\n");
|
||||
predict(inputData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the available data, calculate the relationships between the
|
||||
* items and number of occurences
|
||||
*
|
||||
* @param data
|
||||
* existing user data and their items' ratings
|
||||
*/
|
||||
private static void buildDifferencesMatrix(Map<User, HashMap<Item, Double>> data) {
|
||||
for (HashMap<Item, Double> user : data.values()) {
|
||||
for (Entry<Item, Double> e : user.entrySet()) {
|
||||
if (!diff.containsKey(e.getKey())) {
|
||||
diff.put(e.getKey(), new HashMap<Item, Double>());
|
||||
freq.put(e.getKey(), new HashMap<Item, Integer>());
|
||||
}
|
||||
for (Entry<Item, Double> e2 : user.entrySet()) {
|
||||
int oldCount = 0;
|
||||
if (freq.get(e.getKey()).containsKey(e2.getKey())) {
|
||||
oldCount = freq.get(e.getKey()).get(e2.getKey()).intValue();
|
||||
}
|
||||
double oldDiff = 0.0;
|
||||
if (diff.get(e.getKey()).containsKey(e2.getKey())) {
|
||||
oldDiff = diff.get(e.getKey()).get(e2.getKey()).doubleValue();
|
||||
}
|
||||
double observedDiff = e.getValue() - e2.getValue();
|
||||
freq.get(e.getKey()).put(e2.getKey(), oldCount + 1);
|
||||
diff.get(e.getKey()).put(e2.getKey(), oldDiff + observedDiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Item j : diff.keySet()) {
|
||||
for (Item i : diff.get(j).keySet()) {
|
||||
double oldValue = diff.get(j).get(i).doubleValue();
|
||||
int count = freq.get(j).get(i).intValue();
|
||||
diff.get(j).put(i, oldValue / count);
|
||||
}
|
||||
}
|
||||
printData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on existing data predict all missing ratings. If prediction is not
|
||||
* possible, the value will be equal to -1
|
||||
*
|
||||
* @param data
|
||||
* existing user data and their items' ratings
|
||||
*/
|
||||
private static void predict(Map<User, HashMap<Item, Double>> data) {
|
||||
HashMap<Item, Double> uPred = new HashMap<Item, Double>();
|
||||
HashMap<Item, Integer> uFreq = new HashMap<Item, Integer>();
|
||||
for (Item j : diff.keySet()) {
|
||||
uFreq.put(j, 0);
|
||||
uPred.put(j, 0.0);
|
||||
}
|
||||
for (Entry<User, HashMap<Item, Double>> e : data.entrySet()) {
|
||||
for (Item j : e.getValue().keySet()) {
|
||||
for (Item k : diff.keySet()) {
|
||||
try {
|
||||
double predictedValue = diff.get(k).get(j).doubleValue() + e.getValue().get(j).doubleValue();
|
||||
double finalValue = predictedValue * freq.get(k).get(j).intValue();
|
||||
uPred.put(k, uPred.get(k) + finalValue);
|
||||
uFreq.put(k, uFreq.get(k) + freq.get(k).get(j).intValue());
|
||||
} catch (NullPointerException e1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
HashMap<Item, Double> clean = new HashMap<Item, Double>();
|
||||
for (Item j : uPred.keySet()) {
|
||||
if (uFreq.get(j) > 0) {
|
||||
clean.put(j, uPred.get(j).doubleValue() / uFreq.get(j).intValue());
|
||||
}
|
||||
}
|
||||
for (Item j : InputData.items) {
|
||||
if (e.getValue().containsKey(j)) {
|
||||
clean.put(j, e.getValue().get(j));
|
||||
} else if (!clean.containsKey(j)) {
|
||||
clean.put(j, -1.0);
|
||||
}
|
||||
}
|
||||
outputData.put(e.getKey(), clean);
|
||||
}
|
||||
printData(outputData);
|
||||
}
|
||||
|
||||
private static void printData(Map<User, HashMap<Item, Double>> data) {
|
||||
for (User user : data.keySet()) {
|
||||
System.out.println(user.getUsername() + ":");
|
||||
print(data.get(user));
|
||||
}
|
||||
}
|
||||
|
||||
private static void print(HashMap<Item, Double> hashMap) {
|
||||
NumberFormat formatter = new DecimalFormat("#0.000");
|
||||
for (Item j : hashMap.keySet()) {
|
||||
System.out.println(" " + j.getItemName() + " --> " + formatter.format(hashMap.get(j).doubleValue()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.algorithms.slope_one;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class User {
|
||||
|
||||
private String username;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.baeldung.algorithms.sudoku;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class BacktrackingAlgorithm {
|
||||
|
||||
private static final int BOARD_SIZE = 9;
|
||||
private static final int SUBSECTION_SIZE = 3;
|
||||
private static final int BOARD_START_INDEX = 0;
|
||||
|
||||
private static final int NO_VALUE = 0;
|
||||
private static final int MIN_VALUE = 1;
|
||||
private static final int MAX_VALUE = 9;
|
||||
|
||||
private static int[][] board = {
|
||||
{8, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 3, 6, 0, 0, 0, 0, 0},
|
||||
{0, 7, 0, 0, 9, 0, 2, 0, 0},
|
||||
{0, 5, 0, 0, 0, 7, 0, 0, 0},
|
||||
{0, 0, 0, 0, 4, 5, 7, 0, 0},
|
||||
{0, 0, 0, 1, 0, 0, 0, 3, 0},
|
||||
{0, 0, 1, 0, 0, 0, 0, 6, 8},
|
||||
{0, 0, 8, 5, 0, 0, 0, 1, 0},
|
||||
{0, 9, 0, 0, 0, 0, 4, 0, 0}
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
|
||||
solver.solve(board);
|
||||
solver.printBoard();
|
||||
}
|
||||
|
||||
private void printBoard() {
|
||||
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
|
||||
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
|
||||
System.out.print(board[row][column] + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean solve(int[][] board) {
|
||||
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
|
||||
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
|
||||
if (board[row][column] == NO_VALUE) {
|
||||
for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
|
||||
board[row][column] = k;
|
||||
if (isValid(board, row, column) && solve(board)) {
|
||||
return true;
|
||||
}
|
||||
board[row][column] = NO_VALUE;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValid(int[][] board, int row, int column) {
|
||||
return rowConstraint(board, row) &&
|
||||
columnConstraint(board, column) &&
|
||||
subsectionConstraint(board, row, column);
|
||||
}
|
||||
|
||||
private boolean subsectionConstraint(int[][] board, int row, int column) {
|
||||
boolean[] constraint = new boolean[BOARD_SIZE];
|
||||
int subsectionRowStart = (row / SUBSECTION_SIZE) * SUBSECTION_SIZE;
|
||||
int subsectionRowEnd = subsectionRowStart + SUBSECTION_SIZE;
|
||||
|
||||
int subsectionColumnStart = (column / SUBSECTION_SIZE) * SUBSECTION_SIZE;
|
||||
int subsectionColumnEnd = subsectionColumnStart + SUBSECTION_SIZE;
|
||||
|
||||
for (int r = subsectionRowStart; r < subsectionRowEnd; r++) {
|
||||
for (int c = subsectionColumnStart; c < subsectionColumnEnd; c++) {
|
||||
if (!checkConstraint(board, r, constraint, c)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean columnConstraint(int[][] board, int column) {
|
||||
boolean[] constraint = new boolean[BOARD_SIZE];
|
||||
return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
|
||||
.allMatch(row -> checkConstraint(board, row, constraint, column));
|
||||
}
|
||||
|
||||
private boolean rowConstraint(int[][] board, int row) {
|
||||
boolean[] constraint = new boolean[BOARD_SIZE];
|
||||
return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
|
||||
.allMatch(column -> checkConstraint(board, row, constraint, column));
|
||||
}
|
||||
|
||||
private boolean checkConstraint(int[][] board, int row, boolean[] constraint, int column) {
|
||||
if (board[row][column] != NO_VALUE) {
|
||||
if (!constraint[board[row][column] - 1]) {
|
||||
constraint[board[row][column] - 1] = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.algorithms.sudoku;
|
||||
|
||||
class ColumnNode extends DancingNode {
|
||||
int size;
|
||||
String name;
|
||||
|
||||
ColumnNode(String n) {
|
||||
super();
|
||||
size = 0;
|
||||
name = n;
|
||||
C = this;
|
||||
}
|
||||
|
||||
void cover() {
|
||||
unlinkLR();
|
||||
for (DancingNode i = this.D; i != this; i = i.D) {
|
||||
for (DancingNode j = i.R; j != i; j = j.R) {
|
||||
j.unlinkUD();
|
||||
j.C.size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uncover() {
|
||||
for (DancingNode i = this.U; i != this; i = i.U) {
|
||||
for (DancingNode j = i.L; j != i; j = j.L) {
|
||||
j.C.size++;
|
||||
j.relinkUD();
|
||||
}
|
||||
}
|
||||
relinkLR();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.baeldung.algorithms.sudoku;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class DancingLinks {
|
||||
|
||||
private ColumnNode header;
|
||||
private List<DancingNode> answer;
|
||||
|
||||
private void search(int k) {
|
||||
if (header.R == header) {
|
||||
handleSolution(answer);
|
||||
} else {
|
||||
ColumnNode c = selectColumnNodeHeuristic();
|
||||
c.cover();
|
||||
|
||||
for (DancingNode r = c.D; r != c; r = r.D) {
|
||||
answer.add(r);
|
||||
|
||||
for (DancingNode j = r.R; j != r; j = j.R) {
|
||||
j.C.cover();
|
||||
}
|
||||
|
||||
search(k + 1);
|
||||
|
||||
r = answer.remove(answer.size() - 1);
|
||||
c = r.C;
|
||||
|
||||
for (DancingNode j = r.L; j != r; j = j.L) {
|
||||
j.C.uncover();
|
||||
}
|
||||
}
|
||||
c.uncover();
|
||||
}
|
||||
}
|
||||
|
||||
private ColumnNode selectColumnNodeHeuristic() {
|
||||
int min = Integer.MAX_VALUE;
|
||||
ColumnNode ret = null;
|
||||
for (ColumnNode c = (ColumnNode) header.R; c != header; c = (ColumnNode) c.R) {
|
||||
if (c.size < min) {
|
||||
min = c.size;
|
||||
ret = c;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private ColumnNode makeDLXBoard(boolean[][] grid) {
|
||||
final int COLS = grid[0].length;
|
||||
|
||||
ColumnNode headerNode = new ColumnNode("header");
|
||||
List<ColumnNode> columnNodes = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < COLS; i++) {
|
||||
ColumnNode n = new ColumnNode(Integer.toString(i));
|
||||
columnNodes.add(n);
|
||||
headerNode = (ColumnNode) headerNode.hookRight(n);
|
||||
}
|
||||
headerNode = headerNode.R.C;
|
||||
|
||||
for (boolean[] aGrid : grid) {
|
||||
DancingNode prev = null;
|
||||
for (int j = 0; j < COLS; j++) {
|
||||
if (aGrid[j]) {
|
||||
ColumnNode col = columnNodes.get(j);
|
||||
DancingNode newNode = new DancingNode(col);
|
||||
if (prev == null)
|
||||
prev = newNode;
|
||||
col.U.hookDown(newNode);
|
||||
prev = prev.hookRight(newNode);
|
||||
col.size++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headerNode.size = COLS;
|
||||
|
||||
return headerNode;
|
||||
}
|
||||
|
||||
DancingLinks(boolean[][] cover) {
|
||||
header = makeDLXBoard(cover);
|
||||
}
|
||||
|
||||
public void runSolver() {
|
||||
answer = new LinkedList<>();
|
||||
search(0);
|
||||
}
|
||||
|
||||
private void handleSolution(List<DancingNode> answer) {
|
||||
int[][] result = parseBoard(answer);
|
||||
printSolution(result);
|
||||
}
|
||||
|
||||
private int size = 9;
|
||||
|
||||
private int[][] parseBoard(List<DancingNode> answer) {
|
||||
int[][] result = new int[size][size];
|
||||
for (DancingNode n : answer) {
|
||||
DancingNode rcNode = n;
|
||||
int min = Integer.parseInt(rcNode.C.name);
|
||||
for (DancingNode tmp = n.R; tmp != n; tmp = tmp.R) {
|
||||
int val = Integer.parseInt(tmp.C.name);
|
||||
if (val < min) {
|
||||
min = val;
|
||||
rcNode = tmp;
|
||||
}
|
||||
}
|
||||
int ans1 = Integer.parseInt(rcNode.C.name);
|
||||
int ans2 = Integer.parseInt(rcNode.R.C.name);
|
||||
int r = ans1 / size;
|
||||
int c = ans1 % size;
|
||||
int num = (ans2 % size) + 1;
|
||||
result[r][c] = num;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void printSolution(int[][] result) {
|
||||
int size = result.length;
|
||||
for (int[] aResult : result) {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (int j = 0; j < size; j++) {
|
||||
ret.append(aResult[j]).append(" ");
|
||||
}
|
||||
System.out.println(ret);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.baeldung.algorithms.sudoku;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class DancingLinksAlgorithm {
|
||||
private static final int BOARD_SIZE = 9;
|
||||
private static final int SUBSECTION_SIZE = 3;
|
||||
private static final int NO_VALUE = 0;
|
||||
private static final int CONSTRAINTS = 4;
|
||||
private static final int MIN_VALUE = 1;
|
||||
private static final int MAX_VALUE = 9;
|
||||
private static final int COVER_START_INDEX = 1;
|
||||
|
||||
private static int[][] board = {
|
||||
{8, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 3, 6, 0, 0, 0, 0, 0},
|
||||
{0, 7, 0, 0, 9, 0, 2, 0, 0},
|
||||
{0, 5, 0, 0, 0, 7, 0, 0, 0},
|
||||
{0, 0, 0, 0, 4, 5, 7, 0, 0},
|
||||
{0, 0, 0, 1, 0, 0, 0, 3, 0},
|
||||
{0, 0, 1, 0, 0, 0, 0, 6, 8},
|
||||
{0, 0, 8, 5, 0, 0, 0, 1, 0},
|
||||
{0, 9, 0, 0, 0, 0, 4, 0, 0}
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
DancingLinksAlgorithm solver = new DancingLinksAlgorithm();
|
||||
solver.solve(board);
|
||||
}
|
||||
|
||||
private void solve(int[][] board) {
|
||||
boolean[][] cover = initializeExactCoverBoard(board);
|
||||
DancingLinks dlx = new DancingLinks(cover);
|
||||
dlx.runSolver();
|
||||
}
|
||||
|
||||
private int getIndex(int row, int column, int num) {
|
||||
return (row - 1) * BOARD_SIZE * BOARD_SIZE + (column - 1) * BOARD_SIZE + (num - 1);
|
||||
}
|
||||
|
||||
private boolean[][] createExactCoverBoard() {
|
||||
boolean[][] coverBoard = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS];
|
||||
|
||||
int hBase = 0;
|
||||
hBase = checkCellConstraint(coverBoard, hBase);
|
||||
hBase = checkRowConstraint(coverBoard, hBase);
|
||||
hBase = checkColumnConstraint(coverBoard, hBase);
|
||||
checkSubsectionConstraint(coverBoard, hBase);
|
||||
|
||||
return coverBoard;
|
||||
}
|
||||
|
||||
private int checkSubsectionConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row += SUBSECTION_SIZE) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column += SUBSECTION_SIZE) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
|
||||
for (int rowDelta = 0; rowDelta < SUBSECTION_SIZE; rowDelta++) {
|
||||
for (int columnDelta = 0; columnDelta < SUBSECTION_SIZE; columnDelta++) {
|
||||
int index = getIndex(row + rowDelta, column + columnDelta, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private int checkColumnConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
int index = getIndex(row, column, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private int checkRowConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++) {
|
||||
int index = getIndex(row, column, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private int checkCellConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++, hBase++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) {
|
||||
int index = getIndex(row, column, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private boolean[][] initializeExactCoverBoard(int[][] board) {
|
||||
boolean[][] coverBoard = createExactCoverBoard();
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++) {
|
||||
int n = board[row - 1][column - 1];
|
||||
if (n != NO_VALUE) {
|
||||
for (int num = MIN_VALUE; num <= MAX_VALUE; num++) {
|
||||
if (num != n) {
|
||||
Arrays.fill(coverBoard[getIndex(row, column, num)], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return coverBoard;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.baeldung.algorithms.sudoku;
|
||||
|
||||
class DancingNode {
|
||||
DancingNode L, R, U, D;
|
||||
ColumnNode C;
|
||||
|
||||
DancingNode hookDown(DancingNode node) {
|
||||
assert (this.C == node.C);
|
||||
node.D = this.D;
|
||||
node.D.U = node;
|
||||
node.U = this;
|
||||
this.D = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
DancingNode hookRight(DancingNode node) {
|
||||
node.R = this.R;
|
||||
node.R.L = node;
|
||||
node.L = this;
|
||||
this.R = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
void unlinkLR() {
|
||||
this.L.R = this.R;
|
||||
this.R.L = this.L;
|
||||
}
|
||||
|
||||
void relinkLR() {
|
||||
this.L.R = this.R.L = this;
|
||||
}
|
||||
|
||||
void unlinkUD() {
|
||||
this.U.D = this.D;
|
||||
this.D.U = this.U;
|
||||
}
|
||||
|
||||
void relinkUD() {
|
||||
this.U.D = this.D.U = this;
|
||||
}
|
||||
|
||||
DancingNode() {
|
||||
L = R = U = D = this;
|
||||
}
|
||||
|
||||
DancingNode(ColumnNode c) {
|
||||
this();
|
||||
C = c;
|
||||
}
|
||||
}
|
||||
@@ -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,12 @@
|
||||
S ########
|
||||
# #
|
||||
# ### ## #
|
||||
# # # #
|
||||
# # # # #
|
||||
# ## #####
|
||||
# # #
|
||||
# # # # #
|
||||
##### ####
|
||||
# # E
|
||||
# # # #
|
||||
##########
|
||||
@@ -0,0 +1,22 @@
|
||||
S ##########################
|
||||
# # # #
|
||||
# # #### ############### #
|
||||
# # # # # #
|
||||
# # #### # # ###############
|
||||
# # # # # # #
|
||||
# # # #### ### ########### #
|
||||
# # # # # #
|
||||
# ################## #
|
||||
######### # # # # #
|
||||
# # #### # ####### # #
|
||||
# # ### ### # # # # #
|
||||
# # ## # ##### # #
|
||||
##### ####### # # # # #
|
||||
# # ## ## #### # #
|
||||
# ##### ####### # #
|
||||
# # ############
|
||||
####### ######### # #
|
||||
# # ######## #
|
||||
# ####### ###### ## # E
|
||||
# # # ## #
|
||||
############################
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.baeldung.algorithms;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.algorithms.ga.dijkstra.Dijkstra;
|
||||
import com.baeldung.algorithms.ga.dijkstra.Graph;
|
||||
import com.baeldung.algorithms.ga.dijkstra.Node;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DijkstraAlgorithmLongRunningUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenSPPSolved_thenCorrect() {
|
||||
|
||||
Node nodeA = new Node("A");
|
||||
Node nodeB = new Node("B");
|
||||
Node nodeC = new Node("C");
|
||||
Node nodeD = new Node("D");
|
||||
Node nodeE = new Node("E");
|
||||
Node nodeF = new Node("F");
|
||||
|
||||
nodeA.addDestination(nodeB, 10);
|
||||
nodeA.addDestination(nodeC, 15);
|
||||
|
||||
nodeB.addDestination(nodeD, 12);
|
||||
nodeB.addDestination(nodeF, 15);
|
||||
|
||||
nodeC.addDestination(nodeE, 10);
|
||||
|
||||
nodeD.addDestination(nodeE, 2);
|
||||
nodeD.addDestination(nodeF, 1);
|
||||
|
||||
nodeF.addDestination(nodeE, 5);
|
||||
|
||||
Graph graph = new Graph();
|
||||
|
||||
graph.addNode(nodeA);
|
||||
graph.addNode(nodeB);
|
||||
graph.addNode(nodeC);
|
||||
graph.addNode(nodeD);
|
||||
graph.addNode(nodeE);
|
||||
graph.addNode(nodeF);
|
||||
|
||||
graph = Dijkstra.calculateShortestPathFromSource(graph, nodeA);
|
||||
|
||||
List<Node> shortestPathForNodeB = Arrays.asList(nodeA);
|
||||
List<Node> shortestPathForNodeC = Arrays.asList(nodeA);
|
||||
List<Node> shortestPathForNodeD = Arrays.asList(nodeA, nodeB);
|
||||
List<Node> shortestPathForNodeE = Arrays.asList(nodeA, nodeB, nodeD);
|
||||
List<Node> shortestPathForNodeF = Arrays.asList(nodeA, nodeB, nodeD);
|
||||
|
||||
for (Node node : graph.getNodes()) {
|
||||
switch (node.getName()) {
|
||||
case "B":
|
||||
assertTrue(node
|
||||
.getShortestPath()
|
||||
.equals(shortestPathForNodeB));
|
||||
break;
|
||||
case "C":
|
||||
assertTrue(node
|
||||
.getShortestPath()
|
||||
.equals(shortestPathForNodeC));
|
||||
break;
|
||||
case "D":
|
||||
assertTrue(node
|
||||
.getShortestPath()
|
||||
.equals(shortestPathForNodeD));
|
||||
break;
|
||||
case "E":
|
||||
assertTrue(node
|
||||
.getShortestPath()
|
||||
.equals(shortestPathForNodeE));
|
||||
break;
|
||||
case "F":
|
||||
assertTrue(node
|
||||
.getShortestPath()
|
||||
.equals(shortestPathForNodeF));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.baeldung.algorithms.astar;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class Graph<T extends GraphNode> {
|
||||
private final Set<T> nodes;
|
||||
|
||||
private final Map<String, Set<String>> connections;
|
||||
|
||||
public Graph(Set<T> nodes, Map<String, Set<String>> connections) {
|
||||
this.nodes = nodes;
|
||||
this.connections = connections;
|
||||
}
|
||||
|
||||
public T getNode(String id) {
|
||||
return nodes.stream()
|
||||
.filter(node -> node.getId().equals(id))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No node found with ID"));
|
||||
}
|
||||
|
||||
public Set<T> getConnections(T node) {
|
||||
return connections.get(node.getId()).stream()
|
||||
.map(this::getNode)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.algorithms.astar;
|
||||
|
||||
public interface GraphNode {
|
||||
String getId();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.baeldung.algorithms.astar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class RouteFinder<T extends GraphNode> {
|
||||
private final Graph<T> graph;
|
||||
private final Scorer<T> nextNodeScorer;
|
||||
private final Scorer<T> targetScorer;
|
||||
|
||||
public RouteFinder(Graph<T> graph, Scorer<T> nextNodeScorer, Scorer<T> targetScorer) {
|
||||
this.graph = graph;
|
||||
this.nextNodeScorer = nextNodeScorer;
|
||||
this.targetScorer = targetScorer;
|
||||
}
|
||||
|
||||
public List<T> findRoute(T from, T to) {
|
||||
Map<T, RouteNode<T>> allNodes = new HashMap<>();
|
||||
Queue<RouteNode> openSet = new PriorityQueue<>();
|
||||
|
||||
RouteNode<T> start = new RouteNode<>(from, null, 0d, targetScorer.computeCost(from, to));
|
||||
allNodes.put(from, start);
|
||||
openSet.add(start);
|
||||
|
||||
while (!openSet.isEmpty()) {
|
||||
log.debug("Open Set contains: " + openSet.stream().map(RouteNode::getCurrent).collect(Collectors.toSet()));
|
||||
RouteNode<T> next = openSet.poll();
|
||||
log.debug("Looking at node: " + next);
|
||||
if (next.getCurrent().equals(to)) {
|
||||
log.debug("Found our destination!");
|
||||
|
||||
List<T> route = new ArrayList<>();
|
||||
RouteNode<T> current = next;
|
||||
do {
|
||||
route.add(0, current.getCurrent());
|
||||
current = allNodes.get(current.getPrevious());
|
||||
} while (current != null);
|
||||
|
||||
log.debug("Route: " + route);
|
||||
return route;
|
||||
}
|
||||
|
||||
graph.getConnections(next.getCurrent()).forEach(connection -> {
|
||||
double newScore = next.getRouteScore() + nextNodeScorer.computeCost(next.getCurrent(), connection);
|
||||
RouteNode<T> nextNode = allNodes.getOrDefault(connection, new RouteNode<>(connection));
|
||||
allNodes.put(connection, nextNode);
|
||||
|
||||
if (nextNode.getRouteScore() > newScore) {
|
||||
nextNode.setPrevious(next.getCurrent());
|
||||
nextNode.setRouteScore(newScore);
|
||||
nextNode.setEstimatedScore(newScore + targetScorer.computeCost(connection, to));
|
||||
openSet.add(nextNode);
|
||||
log.debug("Found a better route to node: " + nextNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No route found");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.baeldung.algorithms.astar;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
class RouteNode<T extends GraphNode> implements Comparable<RouteNode> {
|
||||
private final T current;
|
||||
private T previous;
|
||||
private double routeScore;
|
||||
private double estimatedScore;
|
||||
|
||||
RouteNode(T current) {
|
||||
this(current, null, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
RouteNode(T current, T previous, double routeScore, double estimatedScore) {
|
||||
this.current = current;
|
||||
this.previous = previous;
|
||||
this.routeScore = routeScore;
|
||||
this.estimatedScore = estimatedScore;
|
||||
}
|
||||
|
||||
T getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
T getPrevious() {
|
||||
return previous;
|
||||
}
|
||||
|
||||
double getRouteScore() {
|
||||
return routeScore;
|
||||
}
|
||||
|
||||
double getEstimatedScore() {
|
||||
return estimatedScore;
|
||||
}
|
||||
|
||||
void setPrevious(T previous) {
|
||||
this.previous = previous;
|
||||
}
|
||||
|
||||
void setRouteScore(double routeScore) {
|
||||
this.routeScore = routeScore;
|
||||
}
|
||||
|
||||
void setEstimatedScore(double estimatedScore) {
|
||||
this.estimatedScore = estimatedScore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(RouteNode other) {
|
||||
if (this.estimatedScore > other.estimatedScore) {
|
||||
return 1;
|
||||
} else if (this.estimatedScore < other.estimatedScore) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", RouteNode.class.getSimpleName() + "[", "]").add("current=" + current)
|
||||
.add("previous=" + previous).add("routeScore=" + routeScore).add("estimatedScore=" + estimatedScore)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.algorithms.astar;
|
||||
|
||||
public interface Scorer<T extends GraphNode> {
|
||||
double computeCost(T from, T to);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.algorithms.astar.underground;
|
||||
|
||||
import com.baeldung.algorithms.astar.Scorer;
|
||||
|
||||
public class HaversineScorer implements Scorer<Station> {
|
||||
@Override
|
||||
public double computeCost(Station from, Station to) {
|
||||
double R = 6372.8; // In kilometers
|
||||
|
||||
double dLat = Math.toRadians(to.getLatitude() - from.getLatitude());
|
||||
double dLon = Math.toRadians(to.getLongitude() - from.getLongitude());
|
||||
double lat1 = Math.toRadians(from.getLatitude());
|
||||
double lat2 = Math.toRadians(to.getLatitude());
|
||||
|
||||
double a = Math.pow(Math.sin(dLat / 2),2) + Math.pow(Math.sin(dLon / 2),2) * Math.cos(lat1) * Math.cos(lat2);
|
||||
double c = 2 * Math.asin(Math.sqrt(a));
|
||||
return R * c;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,650 @@
|
||||
package com.baeldung.algorithms.astar.underground;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.baeldung.algorithms.astar.Graph;
|
||||
import com.baeldung.algorithms.astar.RouteFinder;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@Slf4j
|
||||
public class RouteFinderIntegrationTest {
|
||||
|
||||
private Graph<Station> underground;
|
||||
|
||||
private RouteFinder<Station> routeFinder;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Set<Station> stations = new HashSet<>();
|
||||
Map<String, Set<String>> connections = new HashMap<>();
|
||||
|
||||
stations.add(new Station("1", "Acton Town", 51.5028, -0.2801));
|
||||
stations.add(new Station("2", "Aldgate", 51.5143, -0.0755));
|
||||
stations.add(new Station("3", "Aldgate East", 51.5154, -0.0726));
|
||||
stations.add(new Station("4", "All Saints", 51.5107, -0.013));
|
||||
stations.add(new Station("5", "Alperton", 51.5407, -0.2997));
|
||||
stations.add(new Station("6", "Amersham", 51.6736, -0.607));
|
||||
stations.add(new Station("7", "Angel", 51.5322, -0.1058));
|
||||
stations.add(new Station("8", "Archway", 51.5653, -0.1353));
|
||||
stations.add(new Station("9", "Arnos Grove", 51.6164, -0.1331));
|
||||
stations.add(new Station("10", "Arsenal", 51.5586, -0.1059));
|
||||
stations.add(new Station("11", "Baker Street", 51.5226, -0.1571));
|
||||
stations.add(new Station("12", "Balham", 51.4431, -0.1525));
|
||||
stations.add(new Station("13", "Bank", 51.5133, -0.0886));
|
||||
stations.add(new Station("14", "Barbican", 51.5204, -0.0979));
|
||||
stations.add(new Station("15", "Barking", 51.5396, 0.081));
|
||||
stations.add(new Station("16", "Barkingside", 51.5856, 0.0887));
|
||||
stations.add(new Station("17", "Barons Court", 51.4905, -0.2139));
|
||||
stations.add(new Station("18", "Bayswater", 51.5121, -0.1879));
|
||||
stations.add(new Station("19", "Beckton", 51.5148, 0.0613));
|
||||
stations.add(new Station("20", "Beckton Park", 51.5087, 0.055));
|
||||
stations.add(new Station("21", "Becontree", 51.5403, 0.127));
|
||||
stations.add(new Station("22", "Belsize Park", 51.5504, -0.1642));
|
||||
stations.add(new Station("23", "Bermondsey", 51.4979, -0.0637));
|
||||
stations.add(new Station("24", "Bethnal Green", 51.527, -0.0549));
|
||||
stations.add(new Station("25", "Blackfriars", 51.512, -0.1031));
|
||||
stations.add(new Station("26", "Blackhorse Road", 51.5867, -0.0417));
|
||||
stations.add(new Station("27", "Blackwall", 51.5079, -0.0066));
|
||||
stations.add(new Station("28", "Bond Street", 51.5142, -0.1494));
|
||||
stations.add(new Station("29", "Borough", 51.5011, -0.0943));
|
||||
stations.add(new Station("30", "Boston Manor", 51.4956, -0.325));
|
||||
stations.add(new Station("31", "Bounds Green", 51.6071, -0.1243));
|
||||
stations.add(new Station("32", "Bow Church", 51.5273, -0.0208));
|
||||
stations.add(new Station("33", "Bow Road", 51.5269, -0.0247));
|
||||
stations.add(new Station("34", "Brent Cross", 51.5766, -0.2136));
|
||||
stations.add(new Station("35", "Brixton", 51.4627, -0.1145));
|
||||
stations.add(new Station("36", "Bromley-By-Bow", 51.5248, -0.0119));
|
||||
stations.add(new Station("37", "Buckhurst Hill", 51.6266, 0.0471));
|
||||
stations.add(new Station("38", "Burnt Oak", 51.6028, -0.2641));
|
||||
stations.add(new Station("39", "Caledonian Road", 51.5481, -0.1188));
|
||||
stations.add(new Station("40", "Camden Town", 51.5392, -0.1426));
|
||||
stations.add(new Station("41", "Canada Water", 51.4982, -0.0502));
|
||||
stations.add(new Station("42", "Canary Wharf", 51.5051, -0.0209));
|
||||
stations.add(new Station("43", "Canning Town", 51.5147, 0.0082));
|
||||
stations.add(new Station("44", "Cannon Street", 51.5113, -0.0904));
|
||||
stations.add(new Station("45", "Canons Park", 51.6078, -0.2947));
|
||||
stations.add(new Station("46", "Chalfont & Latimer", 51.6679, -0.561));
|
||||
stations.add(new Station("47", "Chalk Farm", 51.5441, -0.1538));
|
||||
stations.add(new Station("48", "Chancery Lane", 51.5185, -0.1111));
|
||||
stations.add(new Station("49", "Charing Cross", 51.508, -0.1247));
|
||||
stations.add(new Station("50", "Chesham", 51.7052, -0.611));
|
||||
stations.add(new Station("51", "Chigwell", 51.6177, 0.0755));
|
||||
stations.add(new Station("52", "Chiswick Park", 51.4946, -0.2678));
|
||||
stations.add(new Station("53", "Chorleywood", 51.6543, -0.5183));
|
||||
stations.add(new Station("54", "Clapham Common", 51.4618, -0.1384));
|
||||
stations.add(new Station("55", "Clapham North", 51.4649, -0.1299));
|
||||
stations.add(new Station("56", "Clapham South", 51.4527, -0.148));
|
||||
stations.add(new Station("57", "Cockfosters", 51.6517, -0.1496));
|
||||
stations.add(new Station("58", "Colindale", 51.5955, -0.2502));
|
||||
stations.add(new Station("59", "Colliers Wood", 51.418, -0.1778));
|
||||
stations.add(new Station("60", "Covent Garden", 51.5129, -0.1243));
|
||||
stations.add(new Station("61", "Crossharbour & London Arena", 51.4957, -0.0144));
|
||||
stations.add(new Station("62", "Croxley", 51.647, -0.4412));
|
||||
stations.add(new Station("63", "Custom House", 51.5095, 0.0276));
|
||||
stations.add(new Station("64", "Cutty Sark", 51.4827, -0.0096));
|
||||
stations.add(new Station("65", "Cyprus", 51.5085, 0.064));
|
||||
stations.add(new Station("66", "Dagenham East", 51.5443, 0.1655));
|
||||
stations.add(new Station("67", "Dagenham Heathway", 51.5417, 0.1469));
|
||||
stations.add(new Station("68", "Debden", 51.6455, 0.0838));
|
||||
stations.add(new Station("69", "Deptford Bridge", 51.474, -0.0216));
|
||||
stations.add(new Station("70", "Devons Road", 51.5223, -0.0173));
|
||||
stations.add(new Station("71", "Dollis Hill", 51.552, -0.2387));
|
||||
stations.add(new Station("72", "Ealing Broadway", 51.5152, -0.3017));
|
||||
stations.add(new Station("73", "Ealing Common", 51.5101, -0.2882));
|
||||
stations.add(new Station("74", "Earl's Court", 51.492, -0.1973));
|
||||
stations.add(new Station("75", "Eastcote", 51.5765, -0.397));
|
||||
stations.add(new Station("76", "East Acton", 51.5168, -0.2474));
|
||||
stations.add(new Station("77", "East Finchley", 51.5874, -0.165));
|
||||
stations.add(new Station("78", "East Ham", 51.5394, 0.0518));
|
||||
stations.add(new Station("79", "East India", 51.5093, -0.0021));
|
||||
stations.add(new Station("80", "East Putney", 51.4586, -0.2112));
|
||||
stations.add(new Station("81", "Edgware", 51.6137, -0.275));
|
||||
stations.add(new Station("82", "Edgware Road (B)", 51.5199, -0.1679));
|
||||
stations.add(new Station("83", "Edgware Road (C)", 51.5203, -0.17));
|
||||
stations.add(new Station("84", "Elephant & Castle", 51.4943, -0.1001));
|
||||
stations.add(new Station("85", "Elm Park", 51.5496, 0.1977));
|
||||
stations.add(new Station("86", "Elverson Road", 51.4693, -0.0174));
|
||||
stations.add(new Station("87", "Embankment", 51.5074, -0.1223));
|
||||
stations.add(new Station("88", "Epping", 51.6937, 0.1139));
|
||||
stations.add(new Station("89", "Euston", 51.5282, -0.1337));
|
||||
stations.add(new Station("90", "Euston Square", 51.526, -0.1359));
|
||||
stations.add(new Station("91", "Fairlop", 51.596, 0.0912));
|
||||
stations.add(new Station("92", "Farringdon", 51.5203, -0.1053));
|
||||
stations.add(new Station("93", "Finchley Central", 51.6012, -0.1932));
|
||||
stations.add(new Station("94", "Finchley Road", 51.5472, -0.1803));
|
||||
stations.add(new Station("95", "Finsbury Park", 51.5642, -0.1065));
|
||||
stations.add(new Station("96", "Fulham Broadway", 51.4804, -0.195));
|
||||
stations.add(new Station("97", "Gallions Reach", 51.5096, 0.0716));
|
||||
stations.add(new Station("98", "Gants Hill", 51.5765, 0.0663));
|
||||
stations.add(new Station("99", "Gloucester Road", 51.4945, -0.1829));
|
||||
stations.add(new Station("100", "Golders Green", 51.5724, -0.1941));
|
||||
stations.add(new Station("101", "Goldhawk Road", 51.5018, -0.2267));
|
||||
stations.add(new Station("102", "Goodge Street", 51.5205, -0.1347));
|
||||
stations.add(new Station("103", "Grange Hill", 51.6132, 0.0923));
|
||||
stations.add(new Station("104", "Great Portland Street", 51.5238, -0.1439));
|
||||
stations.add(new Station("105", "Greenford", 51.5423, -0.3456));
|
||||
stations.add(new Station("106", "Greenwich", 51.4781, -0.0149));
|
||||
stations.add(new Station("107", "Green Park", 51.5067, -0.1428));
|
||||
stations.add(new Station("108", "Gunnersbury", 51.4915, -0.2754));
|
||||
stations.add(new Station("109", "Hainault", 51.603, 0.0933));
|
||||
stations.add(new Station("110", "Hammersmith", 51.4936, -0.2251));
|
||||
stations.add(new Station("111", "Hampstead", 51.5568, -0.178));
|
||||
stations.add(new Station("112", "Hanger Lane", 51.5302, -0.2933));
|
||||
stations.add(new Station("113", "Harlesden", 51.5362, -0.2575));
|
||||
stations.add(new Station("114", "Harrow & Wealdston", 51.5925, -0.3351));
|
||||
stations.add(new Station("115", "Harrow-on-the-Hill", 51.5793, -0.3366));
|
||||
stations.add(new Station("116", "Hatton Cross", 51.4669, -0.4227));
|
||||
stations.add(new Station("117", "Heathrow Terminals 1, 2 & 3", 51.4713, -0.4524));
|
||||
stations.add(new Station("118", "Heathrow Terminal 4", 51.4598, -0.4476));
|
||||
stations.add(new Station("119", "Hendon Central", 51.5829, -0.2259));
|
||||
stations.add(new Station("120", "Heron Quays", 51.5033, -0.0215));
|
||||
stations.add(new Station("121", "High Barnet", 51.6503, -0.1943));
|
||||
stations.add(new Station("122", "High Street Kensington", 51.5009, -0.1925));
|
||||
stations.add(new Station("123", "Highbury & Islington", 51.546, -0.104));
|
||||
stations.add(new Station("124", "Highgate", 51.5777, -0.1458));
|
||||
stations.add(new Station("125", "Hillingdon", 51.5538, -0.4499));
|
||||
stations.add(new Station("126", "Holborn", 51.5174, -0.12));
|
||||
stations.add(new Station("127", "Holland Park", 51.5075, -0.206));
|
||||
stations.add(new Station("128", "Holloway Road", 51.5526, -0.1132));
|
||||
stations.add(new Station("129", "Hornchurch", 51.5539, 0.2184));
|
||||
stations.add(new Station("130", "Hounslow Central", 51.4713, -0.3665));
|
||||
stations.add(new Station("131", "Hounslow East", 51.4733, -0.3564));
|
||||
stations.add(new Station("132", "Hounslow West", 51.4734, -0.3855));
|
||||
stations.add(new Station("133", "Hyde Park Corner", 51.5027, -0.1527));
|
||||
stations.add(new Station("134", "Ickenham", 51.5619, -0.4421));
|
||||
stations.add(new Station("135", "Island Gardens", 51.4871, -0.0101));
|
||||
stations.add(new Station("136", "Kennington", 51.4884, -0.1053));
|
||||
stations.add(new Station("137", "Kensal Green", 51.5304, -0.225));
|
||||
stations.add(new Station("138", "Kensington (Olympia)", 51.4983, -0.2106));
|
||||
stations.add(new Station("139", "Kentish Town", 51.5507, -0.1402));
|
||||
stations.add(new Station("140", "Kenton", 51.5816, -0.3162));
|
||||
stations.add(new Station("141", "Kew Gardens", 51.477, -0.285));
|
||||
stations.add(new Station("142", "Kilburn", 51.5471, -0.2047));
|
||||
stations.add(new Station("143", "Kilburn Park", 51.5351, -0.1939));
|
||||
stations.add(new Station("144", "Kingsbury", 51.5846, -0.2786));
|
||||
stations.add(new Station("145", "King's Cross St. Pancras", 51.5308, -0.1238));
|
||||
stations.add(new Station("146", "Knightsbridge", 51.5015, -0.1607));
|
||||
stations.add(new Station("147", "Ladbroke Grove", 51.5172, -0.2107));
|
||||
stations.add(new Station("148", "Lambeth North", 51.4991, -0.1115));
|
||||
stations.add(new Station("149", "Lancaster Gate", 51.5119, -0.1756));
|
||||
stations.add(new Station("150", "Latimer Road", 51.5139, -0.2172));
|
||||
stations.add(new Station("151", "Leicester Square", 51.5113, -0.1281));
|
||||
stations.add(new Station("152", "Lewisham", 51.4657, -0.0142));
|
||||
stations.add(new Station("153", "Leyton", 51.5566, -0.0053));
|
||||
stations.add(new Station("154", "Leytonstone", 51.5683, 0.0083));
|
||||
stations.add(new Station("155", "Limehouse", 51.5123, -0.0396));
|
||||
stations.add(new Station("156", "Liverpool Street", 51.5178, -0.0823));
|
||||
stations.add(new Station("157", "London Bridge", 51.5052, -0.0864));
|
||||
stations.add(new Station("158", "Loughton", 51.6412, 0.0558));
|
||||
stations.add(new Station("159", "Maida Vale", 51.53, -0.1854));
|
||||
stations.add(new Station("160", "Manor House", 51.5712, -0.0958));
|
||||
stations.add(new Station("161", "Mansion House", 51.5122, -0.094));
|
||||
stations.add(new Station("162", "Marble Arch", 51.5136, -0.1586));
|
||||
stations.add(new Station("163", "Marylebone", 51.5225, -0.1631));
|
||||
stations.add(new Station("164", "Mile End", 51.5249, -0.0332));
|
||||
stations.add(new Station("165", "Mill Hill East", 51.6082, -0.2103));
|
||||
stations.add(new Station("166", "Monument", 51.5108, -0.0863));
|
||||
stations.add(new Station("167", "Moorgate", 51.5186, -0.0886));
|
||||
stations.add(new Station("168", "Moor Park", 51.6294, -0.432));
|
||||
stations.add(new Station("169", "Morden", 51.4022, -0.1948));
|
||||
stations.add(new Station("170", "Mornington Crescent", 51.5342, -0.1387));
|
||||
stations.add(new Station("171", "Mudchute", 51.4902, -0.0145));
|
||||
stations.add(new Station("172", "Neasden", 51.5542, -0.2503));
|
||||
stations.add(new Station("173", "Newbury Park", 51.5756, 0.0899));
|
||||
stations.add(new Station("174", "New Cross", 51.4767, -0.0327));
|
||||
stations.add(new Station("175", "New Cross Gate", 51.4757, -0.0402));
|
||||
stations.add(new Station("176", "Northfields", 51.4995, -0.3142));
|
||||
stations.add(new Station("177", "Northolt", 51.5483, -0.3687));
|
||||
stations.add(new Station("178", "Northwick Park", 51.5784, -0.3184));
|
||||
stations.add(new Station("179", "Northwood", 51.6111, -0.424));
|
||||
stations.add(new Station("180", "Northwood Hills", 51.6004, -0.4092));
|
||||
stations.add(new Station("181", "North Acton", 51.5237, -0.2597));
|
||||
stations.add(new Station("182", "North Ealing", 51.5175, -0.2887));
|
||||
stations.add(new Station("183", "North Greenwich", 51.5005, 0.0039));
|
||||
stations.add(new Station("184", "North Harrow", 51.5846, -0.3626));
|
||||
stations.add(new Station("185", "North Wembley", 51.5621, -0.3034));
|
||||
stations.add(new Station("186", "Notting Hill Gate", 51.5094, -0.1967));
|
||||
stations.add(new Station("187", "Oakwood", 51.6476, -0.1318));
|
||||
stations.add(new Station("188", "Old Street", 51.5263, -0.0873));
|
||||
stations.add(new Station("189", "Osterley", 51.4813, -0.3522));
|
||||
stations.add(new Station("190", "Oval", 51.4819, -0.113));
|
||||
stations.add(new Station("191", "Oxford Circus", 51.515, -0.1415));
|
||||
stations.add(new Station("192", "Paddington", 51.5154, -0.1755));
|
||||
stations.add(new Station("193", "Park Royal", 51.527, -0.2841));
|
||||
stations.add(new Station("194", "Parsons Green", 51.4753, -0.2011));
|
||||
stations.add(new Station("195", "Perivale", 51.5366, -0.3232));
|
||||
stations.add(new Station("196", "Picadilly Circus", 51.5098, -0.1342));
|
||||
stations.add(new Station("197", "Pimlico", 51.4893, -0.1334));
|
||||
stations.add(new Station("198", "Pinner", 51.5926, -0.3805));
|
||||
stations.add(new Station("199", "Plaistow", 51.5313, 0.0172));
|
||||
stations.add(new Station("200", "Poplar", 51.5077, -0.0173));
|
||||
stations.add(new Station("201", "Preston Road", 51.572, -0.2954));
|
||||
stations.add(new Station("202", "Prince Regent", 51.5093, 0.0336));
|
||||
stations.add(new Station("203", "Pudding Mill Lane", 51.5343, -0.0139));
|
||||
stations.add(new Station("204", "Putney Bridge", 51.4682, -0.2089));
|
||||
stations.add(new Station("205", "Queen's Park", 51.5341, -0.2047));
|
||||
stations.add(new Station("206", "Queensbury", 51.5942, -0.2861));
|
||||
stations.add(new Station("207", "Queensway", 51.5107, -0.1877));
|
||||
stations.add(new Station("208", "Ravenscourt Park", 51.4942, -0.2359));
|
||||
stations.add(new Station("209", "Rayners Lane", 51.5753, -0.3714));
|
||||
stations.add(new Station("210", "Redbridge", 51.5763, 0.0454));
|
||||
stations.add(new Station("211", "Regent's Park", 51.5234, -0.1466));
|
||||
stations.add(new Station("212", "Richmond", 51.4633, -0.3013));
|
||||
stations.add(new Station("213", "Rickmansworth", 51.6404, -0.4733));
|
||||
stations.add(new Station("214", "Roding Valley", 51.6171, 0.0439));
|
||||
stations.add(new Station("215", "Rotherhithe", 51.501, -0.0525));
|
||||
stations.add(new Station("216", "Royal Albert", 51.5084, 0.0465));
|
||||
stations.add(new Station("217", "Royal Oak", 51.519, -0.188));
|
||||
stations.add(new Station("218", "Royal Victoria", 51.5091, 0.0181));
|
||||
stations.add(new Station("219", "Ruislip", 51.5715, -0.4213));
|
||||
stations.add(new Station("220", "Ruislip Gardens", 51.5606, -0.4103));
|
||||
stations.add(new Station("221", "Ruislip Manor", 51.5732, -0.4125));
|
||||
stations.add(new Station("222", "Russell Square", 51.523, -0.1244));
|
||||
stations.add(new Station("223", "Seven Sisters", 51.5822, -0.0749));
|
||||
stations.add(new Station("224", "Shadwell", 51.5117, -0.056));
|
||||
stations.add(new Station("225", "Shepherd's Bush (C)", 51.5046, -0.2187));
|
||||
stations.add(new Station("226", "Shepherd's Bush (H)", 51.5058, -0.2265));
|
||||
stations.add(new Station("227", "Shoreditch", 51.5227, -0.0708));
|
||||
stations.add(new Station("228", "Sloane Square", 51.4924, -0.1565));
|
||||
stations.add(new Station("229", "Snaresbrook", 51.5808, 0.0216));
|
||||
stations.add(new Station("230", "Southfields", 51.4454, -0.2066));
|
||||
stations.add(new Station("231", "Southgate", 51.6322, -0.128));
|
||||
stations.add(new Station("232", "Southwark", 51.501, -0.1052));
|
||||
stations.add(new Station("233", "South Ealing", 51.5011, -0.3072));
|
||||
stations.add(new Station("234", "South Harrow", 51.5646, -0.3521));
|
||||
stations.add(new Station("235", "South Kensington", 51.4941, -0.1738));
|
||||
stations.add(new Station("236", "South Kenton", 51.5701, -0.3081));
|
||||
stations.add(new Station("237", "South Quay", 51.5007, -0.0191));
|
||||
stations.add(new Station("238", "South Ruislip", 51.5569, -0.3988));
|
||||
stations.add(new Station("239", "South Wimbledon", 51.4154, -0.1919));
|
||||
stations.add(new Station("240", "South Woodford", 51.5917, 0.0275));
|
||||
stations.add(new Station("241", "Stamford Brook", 51.495, -0.2459));
|
||||
stations.add(new Station("242", "Stanmore", 51.6194, -0.3028));
|
||||
stations.add(new Station("243", "Stepney Green", 51.5221, -0.047));
|
||||
stations.add(new Station("244", "Stockwell", 51.4723, -0.123));
|
||||
stations.add(new Station("245", "Stonebridge Park", 51.5439, -0.2759));
|
||||
stations.add(new Station("246", "Stratford", 51.5416, -0.0042));
|
||||
stations.add(new Station("247", "St. James's Park", 51.4994, -0.1335));
|
||||
stations.add(new Station("248", "St. John's Wood", 51.5347, -0.174));
|
||||
stations.add(new Station("249", "St. Paul's", 51.5146, -0.0973));
|
||||
stations.add(new Station("250", "Sudbury Hill", 51.5569, -0.3366));
|
||||
stations.add(new Station("251", "Sudbury Town", 51.5507, -0.3156));
|
||||
stations.add(new Station("252", "Surrey Quays", 51.4933, -0.0478));
|
||||
stations.add(new Station("253", "Swiss Cottage", 51.5432, -0.1738));
|
||||
stations.add(new Station("254", "Temple", 51.5111, -0.1141));
|
||||
stations.add(new Station("255", "Theydon Bois", 51.6717, 0.1033));
|
||||
stations.add(new Station("256", "Tooting Bec", 51.4361, -0.1598));
|
||||
stations.add(new Station("257", "Tooting Broadway", 51.4275, -0.168));
|
||||
stations.add(new Station("258", "Tottenham Court Road", 51.5165, -0.131));
|
||||
stations.add(new Station("259", "Tottenham Hale", 51.5882, -0.0594));
|
||||
stations.add(new Station("260", "Totteridge & Whetstone", 51.6302, -0.1791));
|
||||
stations.add(new Station("261", "Tower Gateway", 51.5106, -0.0743));
|
||||
stations.add(new Station("262", "Tower Hill", 51.5098, -0.0766));
|
||||
stations.add(new Station("263", "Tufnell Park", 51.5567, -0.1374));
|
||||
stations.add(new Station("264", "Turnham Green", 51.4951, -0.2547));
|
||||
stations.add(new Station("265", "Turnpike Lane", 51.5904, -0.1028));
|
||||
stations.add(new Station("266", "Upminster", 51.559, 0.251));
|
||||
stations.add(new Station("267", "Upminster Bridge", 51.5582, 0.2343));
|
||||
stations.add(new Station("268", "Upney", 51.5385, 0.1014));
|
||||
stations.add(new Station("269", "Upton Park", 51.5352, 0.0343));
|
||||
stations.add(new Station("270", "Uxbridge", 51.5463, -0.4786));
|
||||
stations.add(new Station("271", "Vauxhall", 51.4861, -0.1253));
|
||||
stations.add(new Station("272", "Victoria", 51.4965, -0.1447));
|
||||
stations.add(new Station("273", "Walthamstow Central", 51.583, -0.0195));
|
||||
stations.add(new Station("274", "Wanstead", 51.5775, 0.0288));
|
||||
stations.add(new Station("275", "Wapping", 51.5043, -0.0558));
|
||||
stations.add(new Station("276", "Warren Street", 51.5247, -0.1384));
|
||||
stations.add(new Station("277", "Warwick Avenue", 51.5235, -0.1835));
|
||||
stations.add(new Station("278", "Waterloo", 51.5036, -0.1143));
|
||||
stations.add(new Station("279", "Watford", 51.6573, -0.4177));
|
||||
stations.add(new Station("280", "Wembley Central", 51.5519, -0.2963));
|
||||
stations.add(new Station("281", "Wembley Park", 51.5635, -0.2795));
|
||||
stations.add(new Station("282", "Westbourne Park", 51.521, -0.2011));
|
||||
stations.add(new Station("283", "Westferry", 51.5097, -0.0265));
|
||||
stations.add(new Station("284", "Westminster", 51.501, -0.1254));
|
||||
stations.add(new Station("285", "West Acton", 51.518, -0.2809));
|
||||
stations.add(new Station("286", "West Brompton", 51.4872, -0.1953));
|
||||
stations.add(new Station("287", "West Finchley", 51.6095, -0.1883));
|
||||
stations.add(new Station("288", "West Ham", 51.5287, 0.0056));
|
||||
stations.add(new Station("289", "West Hampstead", 51.5469, -0.1906));
|
||||
stations.add(new Station("290", "West Harrow", 51.5795, -0.3533));
|
||||
stations.add(new Station("291", "West India Quay", 51.507, -0.0203));
|
||||
stations.add(new Station("292", "West Kensington", 51.4907, -0.2065));
|
||||
stations.add(new Station("293", "West Ruislip", 51.5696, -0.4376));
|
||||
stations.add(new Station("294", "Whitechapel", 51.5194, -0.0612));
|
||||
stations.add(new Station("295", "White City", 51.512, -0.2239));
|
||||
stations.add(new Station("296", "Willesden Green", 51.5492, -0.2215));
|
||||
stations.add(new Station("297", "Willesden Junction", 51.5326, -0.2478));
|
||||
stations.add(new Station("298", "Wimbledon", 51.4214, -0.2064));
|
||||
stations.add(new Station("299", "Wimbledon Park", 51.4343, -0.1992));
|
||||
stations.add(new Station("300", "Woodford", 51.607, 0.0341));
|
||||
stations.add(new Station("301", "Woodside Park", 51.6179, -0.1856));
|
||||
stations.add(new Station("302", "Wood Green", 51.5975, -0.1097));
|
||||
|
||||
connections.put("1", Stream.of("52","73","73","233","264").collect(Collectors.toSet()));
|
||||
connections.put("2", Stream.of("156","262","156").collect(Collectors.toSet()));
|
||||
connections.put("3", Stream.of("262","294","156","294").collect(Collectors.toSet()));
|
||||
connections.put("4", Stream.of("70","200").collect(Collectors.toSet()));
|
||||
connections.put("5", Stream.of("193","251").collect(Collectors.toSet()));
|
||||
connections.put("6", Stream.of("46").collect(Collectors.toSet()));
|
||||
connections.put("7", Stream.of("145","188").collect(Collectors.toSet()));
|
||||
connections.put("8", Stream.of("124","263").collect(Collectors.toSet()));
|
||||
connections.put("9", Stream.of("31","231").collect(Collectors.toSet()));
|
||||
connections.put("10", Stream.of("95","128").collect(Collectors.toSet()));
|
||||
connections.put("11", Stream.of("163","211","83","104","83","104","28","248","94","104").collect(Collectors.toSet()));
|
||||
connections.put("12", Stream.of("56","256").collect(Collectors.toSet()));
|
||||
connections.put("13", Stream.of("156","249","224","157","167","278").collect(Collectors.toSet()));
|
||||
connections.put("14", Stream.of("92","167","92","167","92","167").collect(Collectors.toSet()));
|
||||
connections.put("15", Stream.of("78","268","78").collect(Collectors.toSet()));
|
||||
connections.put("16", Stream.of("91","173").collect(Collectors.toSet()));
|
||||
connections.put("17", Stream.of("110","292","74","110").collect(Collectors.toSet()));
|
||||
connections.put("18", Stream.of("186","192","186","192").collect(Collectors.toSet()));
|
||||
connections.put("19", Stream.of("97").collect(Collectors.toSet()));
|
||||
connections.put("20", Stream.of("65","216").collect(Collectors.toSet()));
|
||||
connections.put("21", Stream.of("67","268").collect(Collectors.toSet()));
|
||||
connections.put("22", Stream.of("47","111").collect(Collectors.toSet()));
|
||||
connections.put("23", Stream.of("41","157").collect(Collectors.toSet()));
|
||||
connections.put("24", Stream.of("156","164").collect(Collectors.toSet()));
|
||||
connections.put("25", Stream.of("161","254","161","254").collect(Collectors.toSet()));
|
||||
connections.put("26", Stream.of("259","273").collect(Collectors.toSet()));
|
||||
connections.put("27", Stream.of("79","200").collect(Collectors.toSet()));
|
||||
connections.put("28", Stream.of("162","191","11","107").collect(Collectors.toSet()));
|
||||
connections.put("29", Stream.of("84","157").collect(Collectors.toSet()));
|
||||
connections.put("30", Stream.of("176","189").collect(Collectors.toSet()));
|
||||
connections.put("31", Stream.of("9","302").collect(Collectors.toSet()));
|
||||
connections.put("32", Stream.of("70","203").collect(Collectors.toSet()));
|
||||
connections.put("33", Stream.of("36","164","36","164").collect(Collectors.toSet()));
|
||||
connections.put("34", Stream.of("100","119").collect(Collectors.toSet()));
|
||||
connections.put("35", Stream.of("244").collect(Collectors.toSet()));
|
||||
connections.put("36", Stream.of("33","288","33","288").collect(Collectors.toSet()));
|
||||
connections.put("37", Stream.of("158","300").collect(Collectors.toSet()));
|
||||
connections.put("38", Stream.of("58","81").collect(Collectors.toSet()));
|
||||
connections.put("39", Stream.of("128","145").collect(Collectors.toSet()));
|
||||
connections.put("40", Stream.of("47","89","139","170").collect(Collectors.toSet()));
|
||||
connections.put("41", Stream.of("215","252","23","42").collect(Collectors.toSet()));
|
||||
connections.put("42", Stream.of("120","291","41","183").collect(Collectors.toSet()));
|
||||
connections.put("43", Stream.of("79","218","183","288").collect(Collectors.toSet()));
|
||||
connections.put("44", Stream.of("161","166","161","166").collect(Collectors.toSet()));
|
||||
connections.put("45", Stream.of("206","242").collect(Collectors.toSet()));
|
||||
connections.put("46", Stream.of("6","50","53").collect(Collectors.toSet()));
|
||||
connections.put("47", Stream.of("22","40").collect(Collectors.toSet()));
|
||||
connections.put("48", Stream.of("126","249").collect(Collectors.toSet()));
|
||||
connections.put("49", Stream.of("87","196","87","151").collect(Collectors.toSet()));
|
||||
connections.put("50", Stream.of("46").collect(Collectors.toSet()));
|
||||
connections.put("51", Stream.of("103","214").collect(Collectors.toSet()));
|
||||
connections.put("52", Stream.of("1","264").collect(Collectors.toSet()));
|
||||
connections.put("53", Stream.of("46","213").collect(Collectors.toSet()));
|
||||
connections.put("54", Stream.of("55","56").collect(Collectors.toSet()));
|
||||
connections.put("55", Stream.of("54","244").collect(Collectors.toSet()));
|
||||
connections.put("56", Stream.of("12","54").collect(Collectors.toSet()));
|
||||
connections.put("57", Stream.of("187").collect(Collectors.toSet()));
|
||||
connections.put("58", Stream.of("38","119").collect(Collectors.toSet()));
|
||||
connections.put("59", Stream.of("239","257").collect(Collectors.toSet()));
|
||||
connections.put("60", Stream.of("126","151").collect(Collectors.toSet()));
|
||||
connections.put("61", Stream.of("171","237").collect(Collectors.toSet()));
|
||||
connections.put("62", Stream.of("168","279").collect(Collectors.toSet()));
|
||||
connections.put("63", Stream.of("202","218").collect(Collectors.toSet()));
|
||||
connections.put("64", Stream.of("106","135").collect(Collectors.toSet()));
|
||||
connections.put("65", Stream.of("20","97").collect(Collectors.toSet()));
|
||||
connections.put("66", Stream.of("67","85").collect(Collectors.toSet()));
|
||||
connections.put("67", Stream.of("21","66").collect(Collectors.toSet()));
|
||||
connections.put("68", Stream.of("158","255").collect(Collectors.toSet()));
|
||||
connections.put("69", Stream.of("86","106").collect(Collectors.toSet()));
|
||||
connections.put("70", Stream.of("4","32").collect(Collectors.toSet()));
|
||||
connections.put("71", Stream.of("172","296").collect(Collectors.toSet()));
|
||||
connections.put("72", Stream.of("285","73").collect(Collectors.toSet()));
|
||||
connections.put("73", Stream.of("72","1","1","182").collect(Collectors.toSet()));
|
||||
connections.put("74", Stream.of("99","122","138","286","292","17","99").collect(Collectors.toSet()));
|
||||
connections.put("75", Stream.of("209","221","209","221").collect(Collectors.toSet()));
|
||||
connections.put("76", Stream.of("181","295").collect(Collectors.toSet()));
|
||||
connections.put("77", Stream.of("93","124").collect(Collectors.toSet()));
|
||||
connections.put("78", Stream.of("15","269","15","269").collect(Collectors.toSet()));
|
||||
connections.put("79", Stream.of("27","43").collect(Collectors.toSet()));
|
||||
connections.put("80", Stream.of("204","230").collect(Collectors.toSet()));
|
||||
connections.put("81", Stream.of("38").collect(Collectors.toSet()));
|
||||
connections.put("82", Stream.of("163","192").collect(Collectors.toSet()));
|
||||
connections.put("83", Stream.of("11","192","192","11","192").collect(Collectors.toSet()));
|
||||
connections.put("84", Stream.of("148","29","136").collect(Collectors.toSet()));
|
||||
connections.put("85", Stream.of("66","129").collect(Collectors.toSet()));
|
||||
connections.put("86", Stream.of("69","152").collect(Collectors.toSet()));
|
||||
connections.put("87", Stream.of("49","278","254","284","254","284","49","278").collect(Collectors.toSet()));
|
||||
connections.put("88", Stream.of("255").collect(Collectors.toSet()));
|
||||
connections.put("89", Stream.of("40","145","170","276","145","276").collect(Collectors.toSet()));
|
||||
connections.put("90", Stream.of("104","145","104","145","104","145").collect(Collectors.toSet()));
|
||||
connections.put("91", Stream.of("16","109").collect(Collectors.toSet()));
|
||||
connections.put("92", Stream.of("14","145","14","145","14","145").collect(Collectors.toSet()));
|
||||
connections.put("93", Stream.of("77","165","287").collect(Collectors.toSet()));
|
||||
connections.put("94", Stream.of("253","289","11","281").collect(Collectors.toSet()));
|
||||
connections.put("95", Stream.of("10","160","123","223").collect(Collectors.toSet()));
|
||||
connections.put("96", Stream.of("194","286").collect(Collectors.toSet()));
|
||||
connections.put("97", Stream.of("19","65").collect(Collectors.toSet()));
|
||||
connections.put("98", Stream.of("173","210").collect(Collectors.toSet()));
|
||||
connections.put("99", Stream.of("122","235","74","235","74","235").collect(Collectors.toSet()));
|
||||
connections.put("100", Stream.of("34","111").collect(Collectors.toSet()));
|
||||
connections.put("101", Stream.of("110","226").collect(Collectors.toSet()));
|
||||
connections.put("102", Stream.of("258","276").collect(Collectors.toSet()));
|
||||
connections.put("103", Stream.of("51","109").collect(Collectors.toSet()));
|
||||
connections.put("104", Stream.of("11","90","11","90","11","90").collect(Collectors.toSet()));
|
||||
connections.put("105", Stream.of("177","195").collect(Collectors.toSet()));
|
||||
connections.put("106", Stream.of("64","69").collect(Collectors.toSet()));
|
||||
connections.put("107", Stream.of("28","284","133","196","191","272").collect(Collectors.toSet()));
|
||||
connections.put("108", Stream.of("141","264").collect(Collectors.toSet()));
|
||||
connections.put("109", Stream.of("91","103").collect(Collectors.toSet()));
|
||||
connections.put("110", Stream.of("17","208","101","17","264").collect(Collectors.toSet()));
|
||||
connections.put("111", Stream.of("22","100").collect(Collectors.toSet()));
|
||||
connections.put("112", Stream.of("181","195").collect(Collectors.toSet()));
|
||||
connections.put("113", Stream.of("245","297").collect(Collectors.toSet()));
|
||||
connections.put("114", Stream.of("140").collect(Collectors.toSet()));
|
||||
connections.put("115", Stream.of("178","184","290").collect(Collectors.toSet()));
|
||||
connections.put("116", Stream.of("117","118","132").collect(Collectors.toSet()));
|
||||
connections.put("117", Stream.of("116","118").collect(Collectors.toSet()));
|
||||
connections.put("118", Stream.of("116","117").collect(Collectors.toSet()));
|
||||
connections.put("119", Stream.of("34","58").collect(Collectors.toSet()));
|
||||
connections.put("120", Stream.of("42","237").collect(Collectors.toSet()));
|
||||
connections.put("121", Stream.of("260").collect(Collectors.toSet()));
|
||||
connections.put("122", Stream.of("99","186","74","186").collect(Collectors.toSet()));
|
||||
connections.put("123", Stream.of("95","145").collect(Collectors.toSet()));
|
||||
connections.put("124", Stream.of("8","77").collect(Collectors.toSet()));
|
||||
connections.put("125", Stream.of("134","270","134","270").collect(Collectors.toSet()));
|
||||
connections.put("126", Stream.of("48","258","60","222").collect(Collectors.toSet()));
|
||||
connections.put("127", Stream.of("186","225").collect(Collectors.toSet()));
|
||||
connections.put("128", Stream.of("10","39").collect(Collectors.toSet()));
|
||||
connections.put("129", Stream.of("85","267").collect(Collectors.toSet()));
|
||||
connections.put("130", Stream.of("131","132").collect(Collectors.toSet()));
|
||||
connections.put("131", Stream.of("130","189").collect(Collectors.toSet()));
|
||||
connections.put("132", Stream.of("116","130").collect(Collectors.toSet()));
|
||||
connections.put("133", Stream.of("107","146").collect(Collectors.toSet()));
|
||||
connections.put("134", Stream.of("125","219","125","219").collect(Collectors.toSet()));
|
||||
connections.put("135", Stream.of("64","171").collect(Collectors.toSet()));
|
||||
connections.put("136", Stream.of("84","190","278").collect(Collectors.toSet()));
|
||||
connections.put("137", Stream.of("205","297").collect(Collectors.toSet()));
|
||||
connections.put("138", Stream.of("74").collect(Collectors.toSet()));
|
||||
connections.put("139", Stream.of("40","263").collect(Collectors.toSet()));
|
||||
connections.put("140", Stream.of("114","236").collect(Collectors.toSet()));
|
||||
connections.put("141", Stream.of("108","212").collect(Collectors.toSet()));
|
||||
connections.put("142", Stream.of("289","296").collect(Collectors.toSet()));
|
||||
connections.put("143", Stream.of("159","205").collect(Collectors.toSet()));
|
||||
connections.put("144", Stream.of("206","281").collect(Collectors.toSet()));
|
||||
connections.put("145", Stream.of("90","92","90","92","90","92","7","89","39","222","89","123").collect(Collectors.toSet()));
|
||||
connections.put("146", Stream.of("133","235").collect(Collectors.toSet()));
|
||||
connections.put("147", Stream.of("150","282").collect(Collectors.toSet()));
|
||||
connections.put("148", Stream.of("84","278").collect(Collectors.toSet()));
|
||||
connections.put("149", Stream.of("162","207").collect(Collectors.toSet()));
|
||||
connections.put("150", Stream.of("147","226").collect(Collectors.toSet()));
|
||||
connections.put("151", Stream.of("49","258","60","196").collect(Collectors.toSet()));
|
||||
connections.put("152", Stream.of("86").collect(Collectors.toSet()));
|
||||
connections.put("153", Stream.of("154","246").collect(Collectors.toSet()));
|
||||
connections.put("154", Stream.of("153","229","274").collect(Collectors.toSet()));
|
||||
connections.put("155", Stream.of("224","283").collect(Collectors.toSet()));
|
||||
connections.put("156", Stream.of("13","24","2","167","3","167","2","167").collect(Collectors.toSet()));
|
||||
connections.put("157", Stream.of("23","232","13","29").collect(Collectors.toSet()));
|
||||
connections.put("158", Stream.of("37","68").collect(Collectors.toSet()));
|
||||
connections.put("159", Stream.of("143","277").collect(Collectors.toSet()));
|
||||
connections.put("160", Stream.of("95","265").collect(Collectors.toSet()));
|
||||
connections.put("161", Stream.of("25","44","25","44").collect(Collectors.toSet()));
|
||||
connections.put("162", Stream.of("28","149").collect(Collectors.toSet()));
|
||||
connections.put("163", Stream.of("11","82").collect(Collectors.toSet()));
|
||||
connections.put("164", Stream.of("24","246","33","243","33","243").collect(Collectors.toSet()));
|
||||
connections.put("165", Stream.of("93").collect(Collectors.toSet()));
|
||||
connections.put("166", Stream.of("44","262","44","262").collect(Collectors.toSet()));
|
||||
connections.put("167", Stream.of("14","156","14","156","14","156","13","188").collect(Collectors.toSet()));
|
||||
connections.put("168", Stream.of("62","179","213").collect(Collectors.toSet()));
|
||||
connections.put("169", Stream.of("239").collect(Collectors.toSet()));
|
||||
connections.put("170", Stream.of("40","89").collect(Collectors.toSet()));
|
||||
connections.put("171", Stream.of("61","135").collect(Collectors.toSet()));
|
||||
connections.put("172", Stream.of("71","281").collect(Collectors.toSet()));
|
||||
connections.put("173", Stream.of("16","98").collect(Collectors.toSet()));
|
||||
connections.put("174", Stream.of("252").collect(Collectors.toSet()));
|
||||
connections.put("175", Stream.of("252").collect(Collectors.toSet()));
|
||||
connections.put("176", Stream.of("30","233").collect(Collectors.toSet()));
|
||||
connections.put("177", Stream.of("105","238").collect(Collectors.toSet()));
|
||||
connections.put("178", Stream.of("115","201").collect(Collectors.toSet()));
|
||||
connections.put("179", Stream.of("168","180").collect(Collectors.toSet()));
|
||||
connections.put("180", Stream.of("179","198").collect(Collectors.toSet()));
|
||||
connections.put("181", Stream.of("76","112","285").collect(Collectors.toSet()));
|
||||
connections.put("182", Stream.of("73","193").collect(Collectors.toSet()));
|
||||
connections.put("183", Stream.of("42","43").collect(Collectors.toSet()));
|
||||
connections.put("184", Stream.of("115","198").collect(Collectors.toSet()));
|
||||
connections.put("185", Stream.of("236","280").collect(Collectors.toSet()));
|
||||
connections.put("186", Stream.of("127","207","18","122","18","122").collect(Collectors.toSet()));
|
||||
connections.put("187", Stream.of("57","231").collect(Collectors.toSet()));
|
||||
connections.put("188", Stream.of("7","167").collect(Collectors.toSet()));
|
||||
connections.put("189", Stream.of("30","131").collect(Collectors.toSet()));
|
||||
connections.put("190", Stream.of("136","244").collect(Collectors.toSet()));
|
||||
connections.put("191", Stream.of("196","211","28","258","107","276").collect(Collectors.toSet()));
|
||||
connections.put("192", Stream.of("82","277","18","83","18","83","83","217").collect(Collectors.toSet()));
|
||||
connections.put("193", Stream.of("5","182").collect(Collectors.toSet()));
|
||||
connections.put("194", Stream.of("96","204").collect(Collectors.toSet()));
|
||||
connections.put("195", Stream.of("105","112").collect(Collectors.toSet()));
|
||||
connections.put("196", Stream.of("49","191","107","151").collect(Collectors.toSet()));
|
||||
connections.put("197", Stream.of("271","272").collect(Collectors.toSet()));
|
||||
connections.put("198", Stream.of("180","184").collect(Collectors.toSet()));
|
||||
connections.put("199", Stream.of("269","288","269","288").collect(Collectors.toSet()));
|
||||
connections.put("200", Stream.of("4","27","283","291").collect(Collectors.toSet()));
|
||||
connections.put("201", Stream.of("178","281").collect(Collectors.toSet()));
|
||||
connections.put("202", Stream.of("63","216").collect(Collectors.toSet()));
|
||||
connections.put("203", Stream.of("32","246").collect(Collectors.toSet()));
|
||||
connections.put("204", Stream.of("80","194").collect(Collectors.toSet()));
|
||||
connections.put("205", Stream.of("137","143").collect(Collectors.toSet()));
|
||||
connections.put("206", Stream.of("45","144").collect(Collectors.toSet()));
|
||||
connections.put("207", Stream.of("149","186").collect(Collectors.toSet()));
|
||||
connections.put("208", Stream.of("110","241").collect(Collectors.toSet()));
|
||||
connections.put("209", Stream.of("75","290","75","234").collect(Collectors.toSet()));
|
||||
connections.put("210", Stream.of("98","274").collect(Collectors.toSet()));
|
||||
connections.put("211", Stream.of("11","191").collect(Collectors.toSet()));
|
||||
connections.put("212", Stream.of("141").collect(Collectors.toSet()));
|
||||
connections.put("213", Stream.of("53","168").collect(Collectors.toSet()));
|
||||
connections.put("214", Stream.of("51","300").collect(Collectors.toSet()));
|
||||
connections.put("215", Stream.of("41","275").collect(Collectors.toSet()));
|
||||
connections.put("216", Stream.of("20","202").collect(Collectors.toSet()));
|
||||
connections.put("217", Stream.of("192","282").collect(Collectors.toSet()));
|
||||
connections.put("218", Stream.of("43","63").collect(Collectors.toSet()));
|
||||
connections.put("219", Stream.of("134","221","134","221").collect(Collectors.toSet()));
|
||||
connections.put("220", Stream.of("238","293").collect(Collectors.toSet()));
|
||||
connections.put("221", Stream.of("75","219","75","219").collect(Collectors.toSet()));
|
||||
connections.put("222", Stream.of("126","145").collect(Collectors.toSet()));
|
||||
connections.put("223", Stream.of("95","259").collect(Collectors.toSet()));
|
||||
connections.put("224", Stream.of("13","155","261","275","294").collect(Collectors.toSet()));
|
||||
connections.put("225", Stream.of("127","295").collect(Collectors.toSet()));
|
||||
connections.put("226", Stream.of("101","150").collect(Collectors.toSet()));
|
||||
connections.put("227", Stream.of("294").collect(Collectors.toSet()));
|
||||
connections.put("228", Stream.of("235","272","235","272").collect(Collectors.toSet()));
|
||||
connections.put("229", Stream.of("154","240").collect(Collectors.toSet()));
|
||||
connections.put("230", Stream.of("80","299").collect(Collectors.toSet()));
|
||||
connections.put("231", Stream.of("9","187").collect(Collectors.toSet()));
|
||||
connections.put("232", Stream.of("157","278").collect(Collectors.toSet()));
|
||||
connections.put("233", Stream.of("1","176").collect(Collectors.toSet()));
|
||||
connections.put("234", Stream.of("209","250").collect(Collectors.toSet()));
|
||||
connections.put("235", Stream.of("99","228","99","228","99","146").collect(Collectors.toSet()));
|
||||
connections.put("236", Stream.of("140","185").collect(Collectors.toSet()));
|
||||
connections.put("237", Stream.of("61","120").collect(Collectors.toSet()));
|
||||
connections.put("238", Stream.of("177","220").collect(Collectors.toSet()));
|
||||
connections.put("239", Stream.of("59","169").collect(Collectors.toSet()));
|
||||
connections.put("240", Stream.of("229","300").collect(Collectors.toSet()));
|
||||
connections.put("241", Stream.of("208","264").collect(Collectors.toSet()));
|
||||
connections.put("242", Stream.of("45").collect(Collectors.toSet()));
|
||||
connections.put("243", Stream.of("164","294","164","294").collect(Collectors.toSet()));
|
||||
connections.put("244", Stream.of("55","190","35","271").collect(Collectors.toSet()));
|
||||
connections.put("245", Stream.of("113","280").collect(Collectors.toSet()));
|
||||
connections.put("246", Stream.of("153","164","203","288").collect(Collectors.toSet()));
|
||||
connections.put("247", Stream.of("272","284","272","284").collect(Collectors.toSet()));
|
||||
connections.put("248", Stream.of("11","253").collect(Collectors.toSet()));
|
||||
connections.put("249", Stream.of("13","48").collect(Collectors.toSet()));
|
||||
connections.put("250", Stream.of("234","251").collect(Collectors.toSet()));
|
||||
connections.put("251", Stream.of("5","250").collect(Collectors.toSet()));
|
||||
connections.put("252", Stream.of("41","174","175").collect(Collectors.toSet()));
|
||||
connections.put("253", Stream.of("94","248").collect(Collectors.toSet()));
|
||||
connections.put("254", Stream.of("25","87","25","87").collect(Collectors.toSet()));
|
||||
connections.put("255", Stream.of("68","88").collect(Collectors.toSet()));
|
||||
connections.put("256", Stream.of("12","257").collect(Collectors.toSet()));
|
||||
connections.put("257", Stream.of("59","256").collect(Collectors.toSet()));
|
||||
connections.put("258", Stream.of("126","191","102","151").collect(Collectors.toSet()));
|
||||
connections.put("259", Stream.of("26","223").collect(Collectors.toSet()));
|
||||
connections.put("260", Stream.of("121","301").collect(Collectors.toSet()));
|
||||
connections.put("261", Stream.of("224").collect(Collectors.toSet()));
|
||||
connections.put("262", Stream.of("2","166","3","166").collect(Collectors.toSet()));
|
||||
connections.put("263", Stream.of("8","139").collect(Collectors.toSet()));
|
||||
connections.put("264", Stream.of("52","108","241","1","110").collect(Collectors.toSet()));
|
||||
connections.put("265", Stream.of("160","302").collect(Collectors.toSet()));
|
||||
connections.put("266", Stream.of("267").collect(Collectors.toSet()));
|
||||
connections.put("267", Stream.of("129","266").collect(Collectors.toSet()));
|
||||
connections.put("268", Stream.of("15","21").collect(Collectors.toSet()));
|
||||
connections.put("269", Stream.of("78","199","78","199").collect(Collectors.toSet()));
|
||||
connections.put("270", Stream.of("125","125").collect(Collectors.toSet()));
|
||||
connections.put("271", Stream.of("197","244").collect(Collectors.toSet()));
|
||||
connections.put("272", Stream.of("228","247","228","247","107","197").collect(Collectors.toSet()));
|
||||
connections.put("273", Stream.of("26").collect(Collectors.toSet()));
|
||||
connections.put("274", Stream.of("154","210").collect(Collectors.toSet()));
|
||||
connections.put("275", Stream.of("215","224").collect(Collectors.toSet()));
|
||||
connections.put("276", Stream.of("89","102","89","191").collect(Collectors.toSet()));
|
||||
connections.put("277", Stream.of("159","192").collect(Collectors.toSet()));
|
||||
connections.put("278", Stream.of("87","148","232","284","87","136","13").collect(Collectors.toSet()));
|
||||
connections.put("279", Stream.of("62").collect(Collectors.toSet()));
|
||||
connections.put("280", Stream.of("185","245").collect(Collectors.toSet()));
|
||||
connections.put("281", Stream.of("144","172","94","201").collect(Collectors.toSet()));
|
||||
connections.put("282", Stream.of("147","217").collect(Collectors.toSet()));
|
||||
connections.put("283", Stream.of("155","200","291").collect(Collectors.toSet()));
|
||||
connections.put("284", Stream.of("87","247","87","247","107","278").collect(Collectors.toSet()));
|
||||
connections.put("285", Stream.of("72","181").collect(Collectors.toSet()));
|
||||
connections.put("286", Stream.of("74","96").collect(Collectors.toSet()));
|
||||
connections.put("287", Stream.of("93","301").collect(Collectors.toSet()));
|
||||
connections.put("288", Stream.of("36","199","36","199","43","246").collect(Collectors.toSet()));
|
||||
connections.put("289", Stream.of("94","142").collect(Collectors.toSet()));
|
||||
connections.put("290", Stream.of("115","209").collect(Collectors.toSet()));
|
||||
connections.put("291", Stream.of("42","200","283").collect(Collectors.toSet()));
|
||||
connections.put("292", Stream.of("17","74").collect(Collectors.toSet()));
|
||||
connections.put("293", Stream.of("220").collect(Collectors.toSet()));
|
||||
connections.put("294", Stream.of("3","243","224","227","3","243").collect(Collectors.toSet()));
|
||||
connections.put("295", Stream.of("76","225").collect(Collectors.toSet()));
|
||||
connections.put("296", Stream.of("71","142").collect(Collectors.toSet()));
|
||||
connections.put("297", Stream.of("113","137").collect(Collectors.toSet()));
|
||||
connections.put("298", Stream.of("299").collect(Collectors.toSet()));
|
||||
connections.put("299", Stream.of("230","298").collect(Collectors.toSet()));
|
||||
connections.put("300", Stream.of("37","214","240").collect(Collectors.toSet()));
|
||||
connections.put("301", Stream.of("260","287").collect(Collectors.toSet()));
|
||||
connections.put("302", Stream.of("31","265").collect(Collectors.toSet()));
|
||||
|
||||
underground = new Graph<>(stations, connections);
|
||||
routeFinder = new RouteFinder<>(underground, new HaversineScorer(), new HaversineScorer());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findRoute() {
|
||||
List<Station> route = routeFinder.findRoute(underground.getNode("74"), underground.getNode("7"));
|
||||
assertThat(route).size().isPositive();
|
||||
|
||||
route.stream().map(Station::getName).collect(Collectors.toList()).forEach(station -> log.debug(station));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.algorithms.astar.underground;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import com.baeldung.algorithms.astar.GraphNode;
|
||||
|
||||
public class Station implements GraphNode {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
|
||||
public Station(String id, String name, double latitude, double longitude) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", Station.class.getSimpleName() + "[", "]").add("id='" + id + "'")
|
||||
.add("name='" + name + "'").add("latitude=" + latitude).add("longitude=" + longitude).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class EditDistanceDataProvider {
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> getLists() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
{ "", "", 0 },
|
||||
{ "ago", "", 3 },
|
||||
{ "", "do", 2 },
|
||||
{ "abc", "adc", 1 },
|
||||
{ "peek", "pesek", 1 },
|
||||
{ "sunday", "saturday", 3 }
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class EditDistanceUnitTest extends EditDistanceDataProvider {
|
||||
|
||||
private String x;
|
||||
private String y;
|
||||
private int result;
|
||||
|
||||
public EditDistanceUnitTest(String a, String b, int res) {
|
||||
super();
|
||||
x = a;
|
||||
y = b;
|
||||
result = res;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditDistance_RecursiveImplementation() {
|
||||
assertEquals(result, EditDistanceRecursive.calculate(x, y));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditDistance_givenDynamicProgrammingImplementation() {
|
||||
assertEquals(result, EditDistanceDynamicProgramming.calculate(x, y));
|
||||
}
|
||||
}
|
||||
@@ -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 CycleDetectionBruteForceUnitTest extends CycleDetectionTestBase {
|
||||
boolean cycleExists;
|
||||
Node<Integer> head;
|
||||
|
||||
public CycleDetectionBruteForceUnitTest(Node<Integer> head, boolean cycleExists) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenList_detectLoop() {
|
||||
Assert.assertEquals(cycleExists, CycleDetectionBruteForce.detectCycle(head).cycleExists);
|
||||
}
|
||||
}
|
||||
@@ -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 CycleDetectionByFastAndSlowIteratorsUnitTest extends CycleDetectionTestBase {
|
||||
boolean cycleExists;
|
||||
Node<Integer> head;
|
||||
|
||||
public CycleDetectionByFastAndSlowIteratorsUnitTest(Node<Integer> head, boolean cycleExists) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenList_detectLoop() {
|
||||
Assert.assertEquals(cycleExists, CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists);
|
||||
}
|
||||
}
|
||||
@@ -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 CycleDetectionByHashingUnitTest extends CycleDetectionTestBase {
|
||||
boolean cycleExists;
|
||||
Node<Integer> head;
|
||||
|
||||
public CycleDetectionByHashingUnitTest(Node<Integer> head, boolean cycleExists) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenList_detectLoop() {
|
||||
Assert.assertEquals(cycleExists, CycleDetectionByHashing.detectCycle(head).cycleExists);
|
||||
}
|
||||
}
|
||||
@@ -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<Object[]> getLists() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
{ createList(), false },
|
||||
{ createListWithLoop(), true },
|
||||
{ createListWithFullCycle(), true },
|
||||
{ createListWithSingleNodeInCycle(), true }
|
||||
});
|
||||
}
|
||||
|
||||
public static Node<Integer> createList() {
|
||||
Node<Integer> root = Node.createNewNode(10, null);
|
||||
|
||||
for (int i = 9; i >= 1; --i) {
|
||||
Node<Integer> current = Node.createNewNode(i, root);
|
||||
root = current;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public static Node<Integer> createListWithLoop() {
|
||||
Node<Integer> node = createList();
|
||||
createLoop(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
public static Node<Integer> createListWithFullCycle() {
|
||||
Node<Integer> head = createList();
|
||||
Node<Integer> tail = Node.getTail(head);
|
||||
tail.next = head;
|
||||
return head;
|
||||
}
|
||||
|
||||
public static Node<Integer> createListWithSingleNodeInCycle() {
|
||||
Node<Integer> head = createList();
|
||||
Node<Integer> tail = Node.getTail(head);
|
||||
tail.next = tail;
|
||||
return head;
|
||||
}
|
||||
|
||||
public static void createLoop(Node<Integer> root) {
|
||||
Node<Integer> tail = Node.getTail(root);
|
||||
|
||||
Node<Integer> middle = root;
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
middle = middle.next;
|
||||
}
|
||||
|
||||
tail.next = middle;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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 CycleRemovalBruteForceUnitTest extends CycleDetectionTestBase {
|
||||
boolean cycleExists;
|
||||
Node<Integer> head;
|
||||
|
||||
public CycleRemovalBruteForceUnitTest(Node<Integer> head, boolean cycleExists) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenList_ifLoopExists_thenDetectAndRemoveLoop() {
|
||||
Assert.assertEquals(cycleExists, CycleRemovalBruteForce.detectAndRemoveCycle(head));
|
||||
Assert.assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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 CycleRemovalByCountingLoopNodesUnitTest extends CycleDetectionTestBase {
|
||||
boolean cycleExists;
|
||||
Node<Integer> head;
|
||||
|
||||
public CycleRemovalByCountingLoopNodesUnitTest(Node<Integer> head, boolean cycleExists) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenList_ifLoopExists_thenDetectAndRemoveLoop() {
|
||||
Assert.assertEquals(cycleExists, CycleRemovalByCountingLoopNodes.detectAndRemoveCycle(head));
|
||||
Assert.assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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 CycleRemovalWithoutCountingLoopNodesUnitTest extends CycleDetectionTestBase {
|
||||
boolean cycleExists;
|
||||
Node<Integer> head;
|
||||
|
||||
public CycleRemovalWithoutCountingLoopNodesUnitTest(Node<Integer> head, boolean cycleExists) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenList_ifLoopExists_thenDetectAndRemoveLoop() {
|
||||
Assert.assertEquals(cycleExists, CycleRemovalWithoutCountingLoopNodes.detectAndRemoveCycle(head));
|
||||
Assert.assertFalse(CycleDetectionByFastAndSlowIterators.detectCycle(head).cycleExists);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.baeldung.algorithms.moneywords;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.algorithms.numberwordconverter.NumberWordConverter;
|
||||
|
||||
public class NumberWordConverterUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenMoneyNegative_thenReturnInvalidInput() {
|
||||
assertEquals(NumberWordConverter.INVALID_INPUT_GIVEN, NumberWordConverter.getMoneyIntoWords(-13));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenZeroDollarsGiven_thenReturnEmptyString() {
|
||||
assertEquals("", NumberWordConverter.getMoneyIntoWords(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOnlyDollarsGiven_thenReturnWords() {
|
||||
assertEquals("one dollar", NumberWordConverter.getMoneyIntoWords(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOnlyCentsGiven_thenReturnWords() {
|
||||
assertEquals("sixty cents", NumberWordConverter.getMoneyIntoWords(0.6));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAlmostAMillioDollarsGiven_thenReturnWords() {
|
||||
String expectedResult = "nine hundred ninety nine thousand nine hundred ninety nine dollars";
|
||||
assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(999_999));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenThirtyMillionDollarsGiven_thenReturnWords() {
|
||||
String expectedResult = "thirty three million three hundred forty eight thousand nine hundred seventy eight dollars";
|
||||
assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(33_348_978));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTwoBillionDollarsGiven_thenReturnWords() {
|
||||
String expectedResult = "two billion one hundred thirty three million two hundred forty seven thousand eight hundred ten dollars";
|
||||
assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(2_133_247_810));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGivenDollarsAndCents_thenReturnWords() {
|
||||
String expectedResult = "nine hundred twenty four dollars and sixty cents";
|
||||
assertEquals(expectedResult, NumberWordConverter.getMoneyIntoWords(924.6));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOneDollarAndNoCents_thenReturnDollarSingular() {
|
||||
assertEquals("one dollar", NumberWordConverter.getMoneyIntoWords(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNoDollarsAndOneCent_thenReturnCentSingular() {
|
||||
assertEquals("one cent", NumberWordConverter.getMoneyIntoWords(0.01));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNoDollarsAndTwoCents_thenReturnCentsPlural() {
|
||||
assertEquals("two cents", NumberWordConverter.getMoneyIntoWords(0.02));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNoDollarsAndNinetyNineCents_thenReturnWords() {
|
||||
assertEquals("ninety nine cents", NumberWordConverter.getMoneyIntoWords(0.99));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNoDollarsAndNineFiveNineCents_thenCorrectRounding() {
|
||||
assertEquals("ninety six cents", NumberWordConverter.getMoneyIntoWords(0.959));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGivenDollarsAndCents_thenReturnWordsVersionTwo() {
|
||||
assertEquals("three hundred ten £ 00/100", NumberWordConverter.getMoneyIntoWords("310"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.jgrapht;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jgrapht.VertexFactory;
|
||||
import org.jgrapht.alg.HamiltonianCycle;
|
||||
import org.jgrapht.generate.CompleteGraphGenerator;
|
||||
import org.jgrapht.graph.DefaultEdge;
|
||||
import org.jgrapht.graph.SimpleWeightedGraph;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CompleteGraphUnitTest {
|
||||
|
||||
static SimpleWeightedGraph<String, DefaultEdge> completeGraph;
|
||||
static int size = 10;
|
||||
|
||||
@Before
|
||||
public void createCompleteGraph() {
|
||||
completeGraph = new SimpleWeightedGraph<>(DefaultEdge.class);
|
||||
CompleteGraphGenerator<String, DefaultEdge> completeGenerator = new CompleteGraphGenerator<String, DefaultEdge>(size);
|
||||
VertexFactory<String> vFactory = new VertexFactory<String>() {
|
||||
private int id = 0;
|
||||
public String createVertex() {
|
||||
return "v" + id++;
|
||||
}
|
||||
};
|
||||
completeGenerator.generateGraph(completeGraph, vFactory, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompleteGraph_whenGetHamiltonianCyclePath_thenGetVerticeListInSequence() {
|
||||
List<String> verticeList = HamiltonianCycle.getApproximateOptimalForCompleteGraph(completeGraph);
|
||||
assertEquals(verticeList.size(), completeGraph.vertexSet().size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.baeldung.jgrapht;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.jgrapht.DirectedGraph;
|
||||
import org.jgrapht.GraphPath;
|
||||
import org.jgrapht.alg.CycleDetector;
|
||||
import org.jgrapht.alg.KosarajuStrongConnectivityInspector;
|
||||
import org.jgrapht.alg.interfaces.StrongConnectivityAlgorithm;
|
||||
import org.jgrapht.alg.shortestpath.AllDirectedPaths;
|
||||
import org.jgrapht.alg.shortestpath.BellmanFordShortestPath;
|
||||
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
|
||||
import org.jgrapht.graph.DefaultDirectedGraph;
|
||||
import org.jgrapht.graph.DefaultEdge;
|
||||
import org.jgrapht.graph.DirectedSubgraph;
|
||||
import org.jgrapht.traverse.BreadthFirstIterator;
|
||||
import org.jgrapht.traverse.DepthFirstIterator;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DirectedGraphUnitTest {
|
||||
DirectedGraph<String, DefaultEdge> directedGraph;
|
||||
|
||||
@Before
|
||||
public void createDirectedGraph() {
|
||||
directedGraph = new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);
|
||||
IntStream.range(1, 10).forEach(i -> {
|
||||
directedGraph.addVertex("v" + i);
|
||||
});
|
||||
directedGraph.addEdge("v1", "v2");
|
||||
directedGraph.addEdge("v2", "v4");
|
||||
directedGraph.addEdge("v4", "v3");
|
||||
directedGraph.addEdge("v3", "v1");
|
||||
directedGraph.addEdge("v5", "v4");
|
||||
directedGraph.addEdge("v5", "v6");
|
||||
directedGraph.addEdge("v6", "v7");
|
||||
directedGraph.addEdge("v7", "v5");
|
||||
directedGraph.addEdge("v8", "v5");
|
||||
directedGraph.addEdge("v9", "v8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenGetStronglyConnectedSubgraphs_thenPathExistsBetweenStronglyconnectedVertices() {
|
||||
StrongConnectivityAlgorithm<String, DefaultEdge> scAlg = new KosarajuStrongConnectivityInspector<>(directedGraph);
|
||||
List<DirectedSubgraph<String, DefaultEdge>> stronglyConnectedSubgraphs = scAlg.stronglyConnectedSubgraphs();
|
||||
List<String> stronglyConnectedVertices = new ArrayList<>(stronglyConnectedSubgraphs.get(3).vertexSet());
|
||||
|
||||
String randomVertex1 = stronglyConnectedVertices.get(0);
|
||||
String randomVertex2 = stronglyConnectedVertices.get(3);
|
||||
AllDirectedPaths<String, DefaultEdge> allDirectedPaths = new AllDirectedPaths<>(directedGraph);
|
||||
|
||||
List<GraphPath<String, DefaultEdge>> possiblePathList = allDirectedPaths.getAllPaths(randomVertex1, randomVertex2, false, stronglyConnectedVertices.size());
|
||||
assertTrue(possiblePathList.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraphWithCycle_whenCheckCycles_thenDetectCycles() {
|
||||
CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<String, DefaultEdge>(directedGraph);
|
||||
assertTrue(cycleDetector.detectCycles());
|
||||
Set<String> cycleVertices = cycleDetector.findCycles();
|
||||
assertTrue(cycleVertices.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenCreateInstanceDepthFirstIterator_thenGetIterator() {
|
||||
DepthFirstIterator depthFirstIterator = new DepthFirstIterator<>(directedGraph);
|
||||
assertNotNull(depthFirstIterator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenCreateInstanceBreadthFirstIterator_thenGetIterator() {
|
||||
BreadthFirstIterator breadthFirstIterator = new BreadthFirstIterator<>(directedGraph);
|
||||
assertNotNull(breadthFirstIterator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenGetDijkstraShortestPath_thenGetNotNullPath() {
|
||||
DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(directedGraph);
|
||||
List<String> shortestPath = dijkstraShortestPath.getPath("v1", "v4").getVertexList();
|
||||
assertNotNull(shortestPath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDirectedGraph_whenGetBellmanFordShortestPath_thenGetNotNullPath() {
|
||||
BellmanFordShortestPath bellmanFordShortestPath = new BellmanFordShortestPath(directedGraph);
|
||||
List<String> shortestPath = bellmanFordShortestPath.getPath("v1", "v4").getVertexList();
|
||||
assertNotNull(shortestPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.jgrapht;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.jgrapht.GraphPath;
|
||||
import org.jgrapht.alg.cycle.HierholzerEulerianCycle;
|
||||
import org.jgrapht.graph.DefaultEdge;
|
||||
import org.jgrapht.graph.SimpleWeightedGraph;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EulerianCircuitUnitTest {
|
||||
SimpleWeightedGraph<String, DefaultEdge> simpleGraph;
|
||||
|
||||
@Before
|
||||
public void createGraphWithEulerianCircuit() {
|
||||
simpleGraph = new SimpleWeightedGraph<>(DefaultEdge.class);
|
||||
IntStream.range(1, 6).forEach(i -> {
|
||||
simpleGraph.addVertex("v" + i);
|
||||
});
|
||||
IntStream.range(1, 6).forEach(i -> {
|
||||
int endVertexNo = (i + 1) > 5 ? 1 : i + 1;
|
||||
simpleGraph.addEdge("v" + i, "v" + endVertexNo);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGraph_whenCheckEluerianCycle_thenGetResult() {
|
||||
HierholzerEulerianCycle eulerianCycle = new HierholzerEulerianCycle<>();
|
||||
assertTrue(eulerianCycle.isEulerian(simpleGraph));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGraphWithEulerianCircuit_whenGetEulerianCycle_thenGetGraphPath() {
|
||||
HierholzerEulerianCycle eulerianCycle = new HierholzerEulerianCycle<>();
|
||||
GraphPath path = eulerianCycle.getEulerianCycle(simpleGraph);
|
||||
assertTrue(path.getEdgeList().containsAll(simpleGraph.edgeSet()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.baeldung.jgrapht;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.jgrapht.ext.JGraphXAdapter;
|
||||
import org.jgrapht.graph.DefaultDirectedGraph;
|
||||
import org.jgrapht.graph.DefaultEdge;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mxgraph.layout.mxCircleLayout;
|
||||
import com.mxgraph.layout.mxIGraphLayout;
|
||||
import com.mxgraph.util.mxCellRenderer;
|
||||
|
||||
public class GraphImageGenerationUnitTest {
|
||||
static DefaultDirectedGraph<String, DefaultEdge> g;
|
||||
|
||||
@Before
|
||||
public void createGraph() throws IOException {
|
||||
File imgFile = new File("src/test/resources/graph1.png");
|
||||
imgFile.createNewFile();
|
||||
g = new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);
|
||||
String x1 = "x1";
|
||||
String x2 = "x2";
|
||||
String x3 = "x3";
|
||||
g.addVertex(x1);
|
||||
g.addVertex(x2);
|
||||
g.addVertex(x3);
|
||||
g.addEdge(x1, x2);
|
||||
g.addEdge(x2, x3);
|
||||
g.addEdge(x3, x1);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
File imgFile = new File("src/test/resources/graph1.png");
|
||||
imgFile.deleteOnExit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAdaptedGraph_whenWriteBufferedImage_ThenFileShouldExist() throws IOException {
|
||||
JGraphXAdapter<String, DefaultEdge> graphAdapter = new JGraphXAdapter<String, DefaultEdge>(g);
|
||||
mxIGraphLayout layout = new mxCircleLayout(graphAdapter);
|
||||
layout.execute(graphAdapter.getDefaultParent());
|
||||
File imgFile = new File("src/test/resources/graph1.png");
|
||||
BufferedImage image = mxCellRenderer.createBufferedImage(graphAdapter, null, 2, Color.WHITE, true, null);
|
||||
ImageIO.write(image, "PNG", imgFile);
|
||||
assertTrue(imgFile.exists());
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user