Skip to content

Commit 677e0b0

Browse files
committed
v1.0.6
1 parent baabe23 commit 677e0b0

File tree

11 files changed

+129
-10
lines changed

11 files changed

+129
-10
lines changed

.idea/workspace.xml

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Algorithm Visualizer.exe

2.6 KB
Binary file not shown.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ The application is launched by executing _Algorithm.Visualizer.exe_
8787
- Depth-First Search
8888
- Breadth-First Search
8989
- Dijkstra's Algorithm
90+
- A* Search
9091
- Reverse Delete
9192
- Kruskal's Algorithm
9293
- Prim's Algorithm
@@ -111,6 +112,9 @@ The application is launched by executing _Algorithm.Visualizer.exe_
111112
> Instant Dijkstra's algorithm on large graphs
112113
> <img src="./media/dijkstra2.gif" width=800>
113114
115+
> Slow A* Search algorithm on a large graph
116+
> <img src="./media/a_star.gif" width=800>
117+
114118
> Fast Kruskal's algorithm on a large graph
115119
> <img src="./media/kruskal.gif" width=800>
116120

media/a_star.gif

326 KB
Loading

src/Algorithm_Visualizer.jar

2.6 KB
Binary file not shown.

src/main/java/GraphPanel.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ public MOUSE_STATE next() {
4646
private MOUSE_STATE mouseState;
4747
protected Algorithm algorithm;
4848
protected String graphSize;
49-
protected HashMap<Integer, Integer[]> nodeCoords;
5049
protected HashMap<Integer, Shape> nodeShapes;
50+
public HashMap<Integer, Integer[]> nodeCoords;
5151
public String algName;
5252
public boolean isShortPathAlg;
5353
public DefaultUndirectedWeightedGraph<Integer, DefaultWeightedEdge> graph;
@@ -247,6 +247,9 @@ protected void startAlgorithm() {
247247
case "Dijkstra":
248248
algorithm = new Dijkstra(this);
249249
break;
250+
case "A*":
251+
algorithm = new A_Star(this);
252+
break;
250253
case "Reverse Delete":
251254
algorithm = new ReverseDelete(this);
252255
break;

src/main/java/util/Defs.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ public class Defs {
1111

1212
// All algorithms available with the visualizer
1313
public static final List<String> algNames = List.of("Depth-First Search",
14-
"Breadth-First Search", "Dijkstra", "Reverse Delete", "Kruskal", "Prim");
14+
"Breadth-First Search", "Dijkstra", "A*",
15+
"Reverse Delete", "Kruskal", "Prim");
1516

1617
// Maps algorithms to whether they should use minimum connected graphs or not.
1718
public static final Map<String, Boolean> isShortPathAlg =
1819
Collections.unmodifiableMap(Map.ofEntries(
1920
Map.entry("Depth-First Search", true),
2021
Map.entry("Breadth-First Search", true),
2122
Map.entry("Dijkstra", true),
23+
Map.entry("A*", true),
2224
Map.entry("Reverse Delete", false),
2325
Map.entry("Kruskal", false),
2426
Map.entry("Prim", false)));
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package main.java.util.algorithms;
2+
3+
4+
import main.java.GraphPanel;
5+
import org.jgrapht.graph.DefaultWeightedEdge;
6+
7+
import java.util.Arrays;
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
import java.util.PriorityQueue;
11+
12+
/**
13+
* Implements an A* search algorithm to find a shortest path from a
14+
* {@link GraphPanel#sourceNode} to a {@link GraphPanel#targetNode}.
15+
*
16+
* @author Ryan Albertson
17+
*/
18+
public class A_Star extends Algorithm {
19+
20+
21+
/**
22+
* Constructor.
23+
* @param gPanel {@link GraphPanel}.
24+
*/
25+
public A_Star(GraphPanel gPanel) {
26+
27+
super(gPanel);
28+
}
29+
30+
31+
public void runAlgorithm(Integer node) {
32+
33+
// Init distance to reach each node through the search
34+
double[] distanceTo = new double[gPanel.nodeCount];
35+
Arrays.fill(distanceTo, Double.POSITIVE_INFINITY);
36+
distanceTo[node] = 0.0;
37+
38+
// Init estimated remaining distance to target node from each node
39+
double[] distanceAfter = new double[gPanel.nodeCount];
40+
double targetX = gPanel.nodeCoords.get(gPanel.targetNode)[0];
41+
double targetY = gPanel.nodeCoords.get(gPanel.targetNode)[1];
42+
for (int i = 0; i < gPanel.nodeCount; i++) {
43+
double iX = gPanel.nodeCoords.get(i)[0];
44+
double iY = gPanel.nodeCoords.get(i)[1];
45+
double dist = Math.sqrt(Math.pow(Math.abs(iY - targetY), 2) +
46+
Math.pow(Math.abs(iX - targetX), 2));
47+
distanceAfter[i] = dist;
48+
}
49+
50+
// Node priority considers the sum: distance[i] + distanceAfter[i]
51+
Double[] prio = new Double[gPanel.nodeCount];
52+
for (int i = 0; i < gPanel.nodeCount; i++) prio[i] = Double.MAX_VALUE;
53+
54+
boolean[] isExplored = new boolean[gPanel.nodeCount];
55+
56+
// Order of nodes to be visited
57+
PriorityQueue<Integer> nodesQueue = new PriorityQueue<>((node1, node2) ->
58+
prio[node1].compareTo(prio[node2]));
59+
nodesQueue.add(node);
60+
61+
// Store nodes & edges from previous iterations of loop. For animation purposes
62+
Map<Integer, Integer> prevNode = new HashMap<>();
63+
Map<Integer, DefaultWeightedEdge> edgeTo = new HashMap<>();
64+
65+
while (!nodesQueue.isEmpty()) {
66+
Integer currentNode = nodesQueue.poll();
67+
isExplored[currentNode] = true;
68+
DefaultWeightedEdge edgeToCurrentNode = edgeTo.get(currentNode);
69+
if (null != edgeToCurrentNode) gPanel.visitedEdges.add(edgeToCurrentNode);
70+
Integer prev = prevNode.get(currentNode);
71+
if (null != prev) gPanel.path[currentNode] = prev;
72+
73+
for (DefaultWeightedEdge edgeToAdjNode : gPanel.graph.edgesOf(currentNode)) {
74+
if (gPanel.visitedEdges.contains(edgeToAdjNode)) continue;
75+
Integer adjNode = gPanel.graph.getEdgeTarget(edgeToAdjNode);
76+
// Account for directed edges
77+
if (adjNode.equals(currentNode)) {
78+
adjNode = gPanel.graph.getEdgeSource(edgeToAdjNode);
79+
}
80+
if (isExplored[adjNode]) continue;
81+
// Update adjNode's distance if this path is shorter than current
82+
double currentDist = distanceTo[adjNode];
83+
double newDist = distanceTo[currentNode] +
84+
gPanel.graph.getEdgeWeight(edgeToAdjNode);
85+
if (newDist < currentDist) {
86+
distanceTo[adjNode] = newDist;
87+
}
88+
// Update total distance if this estimated path is shorter
89+
double totalDist = distanceTo[adjNode] + distanceAfter[adjNode];
90+
if (totalDist < prio[adjNode]) {
91+
prio[adjNode] = totalDist;
92+
nodesQueue.add(adjNode);
93+
prevNode.put(adjNode, currentNode);
94+
edgeTo.put(adjNode, edgeToAdjNode);
95+
}
96+
}
97+
// Check if user has stopped or paused algorithm
98+
animate();
99+
if (isStopped()) return;
100+
// Stop algorithm if a path to the target has been found
101+
if (currentNode.equals(gPanel.targetNode)) break;
102+
}
103+
}
104+
105+
106+
public void runAlgorithm() {
107+
108+
// This signature isn't needed for this algorithm.
109+
}
110+
}
104 Bytes
Binary file not shown.
45 Bytes
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)