Skip to content

Commit 3c6baf8

Browse files
Merge pull request #355 from srezzag/srezzag-djikstras-algorithm-1
Add files via upload
2 parents 5761fcc + 32fb058 commit 3c6baf8

File tree

4 files changed

+389
-0
lines changed

4 files changed

+389
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
/*
2+
* @author Samy Rezzag
3+
*/
4+
package package;
5+
6+
import java.io.BufferedReader;
7+
import java.io.File;
8+
import java.io.FileNotFoundException;
9+
import java.io.FileReader;
10+
import java.io.IOException;
11+
import java.util.ArrayList;
12+
import java.util.HashMap;
13+
import java.util.Map;
14+
import java.util.NavigableSet;
15+
import java.util.Scanner;
16+
import java.util.TreeSet;
17+
18+
import package.Router;
19+
20+
/*
21+
* This DroneRouter class implements the Router interface. This class is
22+
* responsible for interfacing between user command input and with the Dijsktra
23+
* Algorithm. This class has inner classes of Graph, Edge, and Vertex.
24+
*/
25+
public class DroneRouter implements Router {
26+
27+
// Saves the Drone starting point.
28+
private String startingPoint;
29+
// Graph array which holds all the paths/edges
30+
private Graph.Edge[] GRAPH = null;
31+
32+
// Constructor for DroneRouter
33+
public DroneRouter() {
34+
}
35+
36+
/*
37+
* Finds absolute file path, use buffered reader to count lines to instantiate
38+
* the Graph.Edge GRAPH array's length.
39+
*
40+
* Uses scanner to scan each line and create a edges into Graph.Edge GRAPH
41+
*
42+
* @param routesFilePath path to routing file
43+
*
44+
* @param startingPoint the initial starting point of the drone
45+
*/
46+
@Override
47+
public void loadRoutes(String routesFilePath, String startingPoint) {
48+
this.startingPoint = startingPoint;
49+
String sentence = "";
50+
File file = new File(routesFilePath).getAbsoluteFile();
51+
52+
BufferedReader reader = null;
53+
try {
54+
reader = new BufferedReader(new FileReader(file));
55+
int lines = 0;
56+
while (reader.readLine() != null)
57+
lines++;
58+
reader.close();
59+
GRAPH = new Graph.Edge[lines];
60+
} catch (IOException e1) {
61+
throw new IllegalArgumentException("Illegal Argument Exception, File Not Found: " + routesFilePath);
62+
}
63+
64+
try {
65+
int counter = 0;
66+
Scanner input = new Scanner(file);
67+
while (input.hasNextLine()) {
68+
sentence = input.nextLine();
69+
String[] values = sentence.split("\\s+");
70+
GRAPH[counter] = new Graph.Edge(values[0], values[1], Integer.parseInt(values[2]));
71+
counter++;
72+
}
73+
input.close();
74+
75+
} catch (FileNotFoundException e) {
76+
e.printStackTrace();
77+
}
78+
}
79+
80+
/*
81+
* Finds route. Creates an instance of Graph with the provided Graph.Edge GRAPH
82+
* made by routing file. Runes the dijkstra algorithm in respect to the starting
83+
* point given iniitally.
84+
*
85+
* @param destination to find path to.
86+
*/
87+
@Override
88+
public String[] getRoute(String destination) {
89+
Graph g = new Graph(GRAPH);
90+
g.dijkstra(startingPoint);
91+
92+
return g.printPath(destination);
93+
}
94+
95+
/*
96+
* Finds cost. Creates an instance of Graph with the provided Graph.Edge GRAPH
97+
* made by routing file. Runes the dijkstra algorithm in respect to the starting
98+
* point given iniitally.
99+
*
100+
* @param destination to find path to.
101+
*/
102+
@Override
103+
public int getPathCost(String destination) {
104+
Graph g = new Graph(GRAPH);
105+
g.dijkstra(startingPoint);
106+
107+
return g.printCost(destination);
108+
}
109+
}
110+
111+
class Graph {
112+
// mapping of vertex names to Vertex objects, built from a set of Edges
113+
private final Map<String, Vertex> graph;
114+
private static ArrayList<String> temp = new ArrayList<String>();
115+
private static int cost = 0;
116+
117+
/**
118+
* One edge of the graph (only used by Graph constructor)
119+
*/
120+
public static class Edge {
121+
public final String source, destination;
122+
public final int weight;
123+
124+
public Edge(String source, String destination, int weight) {
125+
this.source = source;
126+
this.destination = destination;
127+
this.weight = weight;
128+
}
129+
}
130+
131+
/**
132+
* One vertex of the graph, with mappings of neighboring vertexes
133+
*/
134+
public static class Vertex implements Comparable<Vertex> {
135+
public final String name;
136+
// MAX_VALUE assumed to be infinity
137+
public int weight = Integer.MAX_VALUE;
138+
public Vertex previous = null;
139+
public final Map<Vertex, Integer> neighbours = new HashMap<>();
140+
141+
public Vertex(String name) {
142+
this.name = name;
143+
}
144+
145+
/*
146+
* Will traverse and calculate which paths are taken to get from source to
147+
* destination. Will add the node/edge to a temp arraylist. Arraylist is
148+
* converted to array and returned.
149+
*
150+
* Will return an empty array if null edge.
151+
*/
152+
private String[] printPath() {
153+
154+
if (this == this.previous) {
155+
temp.add(this.name);
156+
} else if (this.previous == null) {
157+
String[] emptyArray = new String[0];
158+
return emptyArray;
159+
} else {
160+
this.previous.printPath();
161+
temp.add(this.name);
162+
}
163+
String[] path = new String[temp.size()];
164+
path = temp.toArray(path);
165+
return path;
166+
}
167+
168+
/*
169+
* Will traverse and calculate which costs are taken to get from source to
170+
* destination. Will add the node/edge to a running tally.
171+
*
172+
* Will return -1 if null.
173+
*/
174+
private int printCost() {
175+
if (this == this.previous) {
176+
cost += this.weight;
177+
} else if (this.previous == null) {
178+
return Router.NO_ROUTE;
179+
} else {
180+
this.previous.printPath();
181+
cost += this.weight;
182+
}
183+
return cost;
184+
}
185+
186+
public int compareTo(Vertex other) {
187+
if (weight == other.weight)
188+
return name.compareTo(other.name);
189+
190+
return Integer.compare(weight, other.weight);
191+
}
192+
}
193+
194+
/**
195+
* Builds a graph from a set of edges
196+
*/
197+
public Graph(Edge[] edges) {
198+
graph = new HashMap<>(edges.length);
199+
200+
// one pass to find all vertices
201+
for (Edge e : edges) {
202+
if (!graph.containsKey(e.source))
203+
graph.put(e.source, new Vertex(e.source));
204+
if (!graph.containsKey(e.destination))
205+
graph.put(e.destination, new Vertex(e.destination));
206+
}
207+
208+
// another pass to set neighbouring vertices
209+
for (Edge e : edges) {
210+
graph.get(e.source).neighbours.put(graph.get(e.destination), e.weight);
211+
// graph.get(e.destination).neighbours.put(graph.get(e.source), e.weight); //
212+
// also do this for
213+
// an undirected graph
214+
}
215+
}
216+
217+
/**
218+
* Runs dijkstras algorithm with the startPoint specified earlier.
219+
*
220+
* @param startingPoint the vertex to start on.
221+
*/
222+
public void dijkstra(String startingPoint) {
223+
if (!graph.containsKey(startingPoint)) {
224+
throw new IllegalArgumentException("Illegal Argument Exception on value: " + startingPoint);
225+
}
226+
final Vertex source = graph.get(startingPoint);
227+
NavigableSet<Vertex> q = new TreeSet<>();
228+
229+
// set-up vertices
230+
for (Vertex v : graph.values()) {
231+
v.previous = v == source ? source : null;
232+
v.weight = v == source ? 0 : Integer.MAX_VALUE;
233+
q.add(v);
234+
}
235+
dijkstra(q);
236+
}
237+
238+
/**
239+
* Implementation of dijkstra's algorithm using a binary heap.
240+
*/
241+
private void dijkstra(final NavigableSet<Vertex> q) {
242+
Vertex u, v;
243+
while (!q.isEmpty()) {
244+
// vertex with shortest weightance (first iteration will return source)
245+
u = q.pollFirst();
246+
if (u.weight == Integer.MAX_VALUE)
247+
break; // we can ignore u (and any other remaining vertices) since they are unreachable
248+
249+
// look at weightances to each neighbour
250+
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
251+
v = a.getKey(); // the neighbour in this iteration
252+
253+
final int alternateDist = u.weight + a.getValue();
254+
if (alternateDist < v.weight) { // shorter path to neighbour found
255+
q.remove(v);
256+
v.weight = alternateDist;
257+
v.previous = u;
258+
q.add(v);
259+
}
260+
}
261+
}
262+
}
263+
264+
/**
265+
* Helper method to get the path of the vertices taken from stratingPoint to
266+
* destination
267+
*
268+
* @param destination
269+
* @return array
270+
*/
271+
public String[] printPath(String destination) {
272+
if (!graph.containsKey(destination)) {
273+
throw new IllegalArgumentException("Invalid Destination, " + destination);
274+
} else {
275+
Graph.temp = new ArrayList<String>();
276+
return graph.get(destination).printPath();
277+
}
278+
}
279+
280+
/**
281+
* Helper method to get the cost of the vertices taken from stratingPoint to
282+
* destination
283+
*
284+
* @param destination
285+
* @return cost
286+
*/
287+
public int printCost(String destination) {
288+
if (!graph.containsKey(destination)) {
289+
throw new IllegalArgumentException("Invalid Destination, " + destination);
290+
} else {
291+
Graph.cost = 0;
292+
return graph.get(destination).printCost();
293+
}
294+
}
295+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
2+
import static org.junit.jupiter.api.Assertions.assertEquals;
3+
import static org.junit.jupiter.api.Assertions.assertThrows;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
import DroneRouter;
8+
9+
class DroneRouterTest {
10+
11+
@Test
12+
void test() {
13+
Router router = new DroneRouter();
14+
router.loadRoutes("routes0.txt", "A");
15+
assertArrayEquals(new String[] { "A", "B", "G" }, router.getRoute("G"));
16+
assertEquals(17, router.getPathCost("G"));
17+
assertThrows(IllegalArgumentException.class, () -> router.getRoute("Z"));
18+
assertArrayEquals(new String[] {}, router.getRoute("M"));
19+
assertEquals(Router.NO_ROUTE, router.getPathCost("M"));
20+
}
21+
22+
@Test
23+
void test2() {
24+
Router router = new DroneRouter();
25+
router.loadRoutes("routes1.txt", "CHI");
26+
assertArrayEquals(new String[] { "CHI", "MSP", "DEN", "LAS" }, router.getRoute("LAS"));
27+
assertEquals(2600, router.getPathCost("DEN"));
28+
assertThrows(IllegalArgumentException.class, () -> router.getRoute("Z"));
29+
assertArrayEquals(new String[] {}, router.getRoute("STP"));
30+
assertEquals(Router.NO_ROUTE, router.getPathCost("STP"));
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @author Ralph A Foy
3+
*
4+
*/
5+
public interface Router {
6+
7+
/**
8+
* Value indicating there is no path from the source to the specified
9+
* destination
10+
*/
11+
int NO_ROUTE = -1;
12+
13+
/**
14+
* Loads the file containing waypoints pairs and the cost to travel between
15+
* them.
16+
*
17+
* @param routesFilePath path to the routes file
18+
* @param source the waypoint that is the source location, that is, the
19+
* starting point of all routs
20+
* @throws IllegalArgumentException if the file is not accessible or the source
21+
* location does not exist
22+
*/
23+
void loadRoutes(String routesFilePath, String source);
24+
25+
/**
26+
* Returns the route from the designated source waypoint to the specified
27+
* destination
28+
*
29+
* @param destination endpoint of route
30+
* @return array of waypoints representing the least expensive route from the
31+
* source to the destination (inclusive). The array is empty if no path
32+
* exists.
33+
* @throws IllegalArgumentException if destination does not exist in the route
34+
* file
35+
*/
36+
String[] getRoute(String destination);
37+
38+
/**
39+
* Returns the cost of the shortest route from the designated source waypoint to
40+
* the specified destination
41+
*
42+
* @param destination endpoint of route from the source waypoint
43+
* @return the cost in units, or {@link NO_ROUTE} if no route exists from the
44+
* source to the specified destination
45+
* @throws IllegalArgumentException if destination does not exist in the route
46+
* file
47+
* @throws NullPointerException if destination is {@code null}
48+
*/
49+
int getPathCost(String destination);
50+
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
A B 5
2+
B C 10
3+
B G 12
4+
G C 5
5+
C D 15
6+
C E 2
7+
D F 4
8+
G E 2
9+
E F 2
10+
A E 3
11+
L M 10

0 commit comments

Comments
 (0)