diff --git a/dijkstra-algorithm/pom.xml b/dijkstra-algorithm/pom.xml new file mode 100644 index 0000000..0491324 --- /dev/null +++ b/dijkstra-algorithm/pom.xml @@ -0,0 +1,15 @@ + + + + java-core-exercises + com.bobocode + 1.0-SNAPSHOT + + 4.0.0 + + dijkstra-algorithm + + + \ No newline at end of file diff --git a/dijkstra-algorithm/src/main/java/com/bobocode/GraphImpl.java b/dijkstra-algorithm/src/main/java/com/bobocode/GraphImpl.java new file mode 100644 index 0000000..fa74bd4 --- /dev/null +++ b/dijkstra-algorithm/src/main/java/com/bobocode/GraphImpl.java @@ -0,0 +1,75 @@ +package com.bobocode; + +import com.bobocode.interfaces.Graph; + +import java.util.Set; + +/** + * {@link GraphImpl} implements Graph {@link Graph}, using nodes as vertices. Nodes are stores in instances of nested + * class Node. The graph can be initialized from a file, or by calling methods to add a node {@link GraphImpl#addNode(String)} + * and add an edge {@link GraphImpl#addDestination(String, String, int)} + * + */ +public class GraphImpl implements Graph { + + /** + * This method creates a Graph from file + * + * File format e.g. + * nodeA nodeB nodeC + * nodeA nodeB 1 + * nodeA nodeC 12 + * @param fileName file contains graph struct + * @return a new graph contains vertices and edges + */ + @Override + public Graph fromFile(String fileName) { + throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + } + + /** + * Adds a node to the graph, if it doesn't exist + * + * @param nodeName name of node to add + */ + @Override + public void addNode(String nodeName) { + throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + } + + /** + * Adds a edge to the graph between nodes + * + * @param nodeFromName name of first node in edge + * @param nodeToName name of second node in edge + * @param distance the weight of edge + */ + @Override + public void addDestination(String nodeFromName, String nodeToName, int distance) { + throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + } + + /** + * Calculates shortest distance between two nodes + * + * @param nodeStart name of node start path + * @param nodeEnd name of node finish path + * @return min distance between two nodes + */ + @Override + public int calculateShortestDistance(String nodeStart, String nodeEnd) { + throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + } + + /** + * Calculates shortest path between two nodes + * + * @param nodeStart name of node start path + * @param nodeEnd name of node finish path + * @return set of nodes, contains min path between two nodes + */ + @Override + public Set calculateShortestPath(String nodeStart, String nodeEnd) { + throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + } +} diff --git a/dijkstra-algorithm/src/main/java/com/bobocode/exceptions/IncorrectDistanceException.java b/dijkstra-algorithm/src/main/java/com/bobocode/exceptions/IncorrectDistanceException.java new file mode 100644 index 0000000..9c027c1 --- /dev/null +++ b/dijkstra-algorithm/src/main/java/com/bobocode/exceptions/IncorrectDistanceException.java @@ -0,0 +1,7 @@ +package com.bobocode.exceptions; + +public class IncorrectDistanceException extends RuntimeException { + public IncorrectDistanceException(String message) { + super(message); + } +} diff --git a/dijkstra-algorithm/src/main/java/com/bobocode/exceptions/NodeNotFoundException.java b/dijkstra-algorithm/src/main/java/com/bobocode/exceptions/NodeNotFoundException.java new file mode 100644 index 0000000..7f5e860 --- /dev/null +++ b/dijkstra-algorithm/src/main/java/com/bobocode/exceptions/NodeNotFoundException.java @@ -0,0 +1,7 @@ +package com.bobocode.exceptions; + +public class NodeNotFoundException extends RuntimeException { + public NodeNotFoundException(String message) { + super(message); + } +} diff --git a/dijkstra-algorithm/src/main/java/com/bobocode/interfaces/Graph.java b/dijkstra-algorithm/src/main/java/com/bobocode/interfaces/Graph.java new file mode 100644 index 0000000..5a0b9de --- /dev/null +++ b/dijkstra-algorithm/src/main/java/com/bobocode/interfaces/Graph.java @@ -0,0 +1,55 @@ +package com.bobocode.interfaces; + +import java.util.Set; +/** + * Graph is a structure amounting to a set of objects in which some pairs of the objects are in some sense "related". + */ +public interface Graph { + /** + * Adds new vertices in graph. + * + * @param nodeName the name of node to add + */ + void addNode(String nodeName); + + /** + * Adds edge between two vertices. + * + * @param nodeFromName the name of first node in edge + * @param nodeToName the name of second node in edge + * @param distance distance between vertices + */ + void addDestination(String nodeFromName, String nodeToName, int distance); + + /** + * Returns shortest distance between two vertices + * + * @param nodeStart the name of start node + * @param nodeEnd the name of finish node + * @return an integer value that is distance between vertices + */ + int calculateShortestDistance(String nodeStart, String nodeEnd); + + /** + * Returns shortest path between two vertices + * + * @param nodeStart the name of start node + * @param nodeEnd the name of finish node + * @return a set that contains node names for shortest path between vertices + */ + Set calculateShortestPath(String nodeStart, String nodeEnd); + + /** + * Returns configured Graph from file + * + * File format e.g. + * nodeA nodeB nodeC + * + * nodeA nodeB 1 + * nodeA nodeC 12 + * + * @param fileName the name of file, which contains graph + * @return a graph that contains vertices from file + */ + Graph fromFile(String fileName); +} diff --git a/dijkstra-algorithm/src/test/java/com/bobocode/GraphImplTest.java b/dijkstra-algorithm/src/test/java/com/bobocode/GraphImplTest.java new file mode 100644 index 0000000..48fe7f6 --- /dev/null +++ b/dijkstra-algorithm/src/test/java/com/bobocode/GraphImplTest.java @@ -0,0 +1,161 @@ +package com.bobocode; + +import com.bobocode.exceptions.IncorrectDistanceException; +import com.bobocode.exceptions.NodeNotFoundException; +import com.bobocode.interfaces.Graph; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GraphImplTest { + public static final String NODE_NOT_FOUND_MSG_PREFIX = "Cannot find Node with name=%s"; + private Graph graph = new GraphImpl(); + + @Test + public void testCalculateShortestDistanceBetweenNodes() { + graph.addNode("nodeA"); + graph.addNode("nodeB"); + graph.addNode("nodeC"); + graph.addNode("nodeD"); + graph.addNode("nodeE"); + graph.addNode("nodeF"); + + graph.addDestination("nodeA", "nodeB", 2); + graph.addDestination("nodeA", "nodeC", 4); + graph.addDestination("nodeA", "nodeD", 5); + + graph.addDestination("nodeB", "nodeE", 7); + graph.addDestination("nodeB", "nodeC", 1); + + graph.addDestination("nodeC", "nodeD", 3); + graph.addDestination("nodeC", "nodeF", 4); + + graph.addDestination("nodeD", "nodeF", 2); + graph.addDestination("nodeE", "nodeF", 8); + + assertEquals(graph.calculateShortestDistance("nodeA", "nodeF"), 7); + assertEquals(graph.calculateShortestDistance("nodeA", "nodeE"), 9); + } + + @Test + public void testCalculateShortestPathBetweenNodes() { + graph.addNode("nodeA"); + graph.addNode("nodeB"); + graph.addNode("nodeC"); + graph.addNode("nodeD"); + graph.addNode("nodeE"); + graph.addNode("nodeF"); + + graph.addDestination("nodeA", "nodeB", 2); + graph.addDestination("nodeA", "nodeC", 4); + graph.addDestination("nodeA", "nodeD", 5); + + graph.addDestination("nodeB", "nodeE", 7); + graph.addDestination("nodeB", "nodeC", 1); + + graph.addDestination("nodeC", "nodeD", 3); + graph.addDestination("nodeC", "nodeF", 4); + + graph.addDestination("nodeD", "nodeF", 2); + graph.addDestination("nodeE", "nodeF", 8); + + assertEquals(graph.calculateShortestPath("nodeA", "nodeF"), Set.of("nodeA", "nodeD", "nodeF")); + } + + @Test + public void testCalculateShortestDistanceInEmptyGraph() { + graph.addNode("nodeA"); + graph.addNode("nodeB"); + graph.addNode("nodeC"); + graph.addNode("nodeD"); + graph.addNode("nodeE"); + graph.addNode("nodeF"); + + assertEquals(graph.calculateShortestDistance("nodeA", "nodeF"), Integer.MAX_VALUE); + assertEquals(graph.calculateShortestDistance("nodeA", "nodeE"), Integer.MAX_VALUE); + + assertNull(graph.calculateShortestPath("nodeA", "nodeF")); + } + + @Test + public void testCalculateShortestDistanceInGraphWithoutNodes() { + try { + graph.calculateShortestDistance("nodeA", "nodeF"); + fail("Should throw exception"); + } catch (NodeNotFoundException e) { + assertEquals(String.format(NODE_NOT_FOUND_MSG_PREFIX, "nodeA"), e.getMessage()); + } catch (Exception e) { + fail("Exception must be NodeNotFoundException"); + } + } + + @Test + public void testCalculateShortestPathInGraphWithoutNodes() { + try { + graph.calculateShortestPath("nodeA", "nodeF"); + fail("Should throw exception"); + } catch (NodeNotFoundException e) { + assertEquals(String.format(NODE_NOT_FOUND_MSG_PREFIX, "nodeA"), e.getMessage()); + } catch (Exception e) { + fail("Exception must be NodeNotFoundException"); + } + } + + @Test + public void testNotConnectedNodeIntoGraph() { + graph.addNode("nodeA"); + graph.addNode("nodeB"); + graph.addNode("nodeC"); + graph.addNode("nodeD"); + + graph.addDestination("nodeA", "nodeB", 3); + graph.addDestination("nodeA", "nodeC", 10); + + graph.addDestination("nodeB", "nodeC", 6); + graph.addDestination("nodeC", "nodeB", 6); + + assertEquals(graph.calculateShortestDistance("nodeA", "nodeC"), 9); + assertEquals(graph.calculateShortestDistance("nodeA", "nodeD"), Integer.MAX_VALUE); + + assertEquals(graph.calculateShortestPath("nodeA", "nodeC"), Set.of("nodeA", "nodeB", "nodeC")); + } + + @Test + public void testAddDistanceWithoutNode() { + + try { + graph.addDestination("nodeA", "nodeB", -1); + fail("Should throw exception"); + } catch (NodeNotFoundException e) { + assertEquals(String.format(NODE_NOT_FOUND_MSG_PREFIX, "nodeA"), e.getMessage()); + } catch (Exception e) { + fail("Exception must be NodeNotFoundException"); + } + } + + @Test + public void testIncorrectDistanceIntoGraph() { + graph.addNode("nodeA"); + graph.addNode("nodeB"); + + try { + graph.addDestination("nodeA", "nodeB", -1); + fail("Should throw exception"); + } catch (IncorrectDistanceException e) { + // Correct situation + } catch (Exception e) { + fail("Exception must be IncorrectDistanceException"); + } + } + + @Test + public void testCorrectCalculateGraphFromFile() { + graph = graph.fromFile("graph.txt"); + + assertEquals(graph.calculateShortestDistance("nodeA", "nodeG"), 19); + assertEquals(graph.calculateShortestPath("nodeA", "nodeC"), Set.of("nodeA", "nodeC", "nodeE", "nodeG")); + } +} \ No newline at end of file diff --git a/linked-queue/src/test/resources/graph.txt b/linked-queue/src/test/resources/graph.txt new file mode 100644 index 0000000..dd786ba --- /dev/null +++ b/linked-queue/src/test/resources/graph.txt @@ -0,0 +1,12 @@ +nodeA nodeB nodeC nodeD nodeE nodeF nodeG +nodeA nodeB 10 +nodeA nodeC 8 +nodeB nodeD 3 +nodeC nodeE 8 +nodeC nodeF 16 +nodeC nodeG 25 +nodeD nodeE 5 +nodeD nodeF 3 +nodeE nodeF 2 +nodeE nodeG 3 +nodeF nodeG 6 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 233439d..e650bdc 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ declarative-sum-of-squares crazy-lambdas crazy-optionals + dijkstra-algorithm pom