-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDijkstraGraph.java
More file actions
151 lines (132 loc) · 6.1 KB
/
DijkstraGraph.java
File metadata and controls
151 lines (132 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// === CS400 File Header Information ===
// Name: Ryan Murphy
// Email: rjmurphy8@wisc.edu
// Group and Team: <your group name: two letters, and team color>
// Group TA: <name of your group's ta>
// Lecturer: Florian Heimerl
// Notes to Grader: <optional extra notes>
import java.util.PriorityQueue;
import java.util.List;
import java.util.LinkedList;
import java.util.NoSuchElementException;
/**
* This class extends the BaseGraph data structure with additional methods for
* computing the total cost and list of node data along the shortest path
* connecting a provided starting to ending nodes. This class makes use of
* Dijkstra's shortest path algorithm.
*/
public class DijkstraGraph<NodeType, EdgeType extends Number>
extends BaseGraph<NodeType, EdgeType>
implements GraphADT<NodeType, EdgeType> {
/**
* While searching for the shortest path between two nodes, a SearchNode
* contains data about one specific path between the start node and another
* node in the graph. The final node in this path is stored in its node
* field. The total cost of this path is stored in its cost field. And the
* predecessor SearchNode within this path is referened by the predecessor
* field (this field is null within the SearchNode containing the starting
* node in its node field).
* <p>
* SearchNodes are Comparable and are sorted by cost so that the lowest cost
* SearchNode has the highest priority within a java.util.PriorityQueue.
*/
protected class SearchNode implements Comparable<SearchNode> {
public Node node;
public double cost;
public SearchNode predecessor;
public SearchNode(Node node, double cost, SearchNode predecessor) {
this.node = node;
this.cost = cost;
this.predecessor = predecessor;
}
public int compareTo(SearchNode other) {
if (cost > other.cost)
return +1;
if (cost < other.cost)
return -1;
return 0;
}
}
/**
* Constructor that sets the map that the graph uses.
*/
public DijkstraGraph() {
super(new PlaceholderMap<>());
}
/**
* This helper method creates a network of SearchNodes while computing the
* shortest path between the provided start and end locations. The
* SearchNode that is returned by this method is represents the end of the
* shortest path that is found: it's cost is the cost of that shortest path,
* and the nodes linked together through predecessor references represent
* all of the nodes along that shortest path (ordered from end to start).
*
* @param start the data item in the starting node for the path
* @param end the data item in the destination node for the path
* @return SearchNode for the final end node within the shortest path
* @throws NoSuchElementException when no path from start to end is found
* or when either start or end data do not
* correspond to a graph node
*/
protected SearchNode computeShortestPath(NodeType start, NodeType end) {
// Are the start and end nodes in graph?
if (!nodes.containsKey(start) || !nodes.containsKey(end))
throw new NoSuchElementException("Start or end node not in graph");
// Initialize helper variables
PriorityQueue<SearchNode> pq = new PriorityQueue<>();
MapADT<NodeType, SearchNode> alreadyVisited = new PlaceholderMap<>();
SearchNode currPath = null;
pq.add(new SearchNode(nodes.get(start), 0, null));
do {
// Throws a NoSuchElementException if pq is null (Cover all reachable nodes)
SearchNode temp = pq.remove();
// Passes over the iteration if the node is already visited
if (alreadyVisited.containsKey(temp.node.data))
continue;
currPath = temp;
alreadyVisited.put(currPath.node.data, currPath);
// Did the path each its destination
if (currPath.node.data.equals(end))
return currPath;
// Adds more nodes to the priority queue
for (Edge edge : currPath.node.edgesLeaving)
pq.add(new SearchNode(nodes.get(edge.successor.data), currPath.cost + edge.data.doubleValue(),
currPath));
} while (true);
}
/**
* Returns the list of data values from nodes along the shortest path
* from the node with the provided start value through the node with the
* provided end value. This list of data values starts with the start
* value, ends with the end value, and contains intermediary values in the
* order they are encountered while traversing this shorteset path. This
* method uses Dijkstra's shortest path algorithm to find this solution.
*
* @param start the data item in the starting node for the path
* @param end the data item in the destination node for the path
* @return list of data item from node along this shortest path
*/
public List<NodeType> shortestPathData(NodeType start, NodeType end) {
SearchNode path = computeShortestPath(start, end);
List<NodeType> nodesInPath = new LinkedList<>();
// Reverses the order of the path and puts the keys into a linked list
while (path != null) {
nodesInPath.add(0, path.node.data);
path = path.predecessor;
}
return nodesInPath;
}
/**
* Returns the cost of the path (sum over edge weights) of the shortest
* path freom the node containing the start data to the node containing the
* end data. This method uses Dijkstra's shortest path algorithm to find
* this solution.
*
* @param start the data item in the starting node for the path
* @param end the data item in the destination node for the path
* @return the cost of the shortest path between these nodes
*/
public double shortestPathCost(NodeType start, NodeType end) {
return computeShortestPath(start, end).cost;
}
}