1
- /*
2
- Time Complexity = O(E), where E is equal to the number of edges
3
- */
4
1
package com .thealgorithms .datastructures .graphs ;
5
2
6
3
import java .util .ArrayList ;
7
- import java .util .Arrays ;
8
4
import java .util .Comparator ;
9
5
import java .util .List ;
10
6
import java .util .PriorityQueue ;
11
7
8
+ /**
9
+ * AStar class implements the A* pathfinding algorithm to find the shortest path in a graph.
10
+ * The graph is represented using an adjacency list, and the algorithm uses a heuristic to estimate
11
+ * the cost to reach the destination node.
12
+ * Time Complexity = O(E), where E is equal to the number of edges
13
+ */
12
14
public final class AStar {
13
15
private AStar () {
14
16
}
15
17
16
- private static class Graph {
17
-
18
- // Graph's structure can be changed only applying changes to this class.
19
-
18
+ /**
19
+ * Represents a graph using an adjacency list.
20
+ */
21
+ static class Graph {
20
22
private ArrayList <ArrayList <Edge >> graph ;
21
23
22
- // Initialise ArrayLists in Constructor
23
24
Graph (int size ) {
24
25
this .graph = new ArrayList <>();
25
26
for (int i = 0 ; i < size ; i ++) {
@@ -31,15 +32,17 @@ private ArrayList<Edge> getNeighbours(int from) {
31
32
return this .graph .get (from );
32
33
}
33
34
34
- // Graph is bidirectional, for just one direction remove second instruction of this method.
35
+ // Add a bidirectional edge to the graph
35
36
private void addEdge (Edge edge ) {
36
37
this .graph .get (edge .getFrom ()).add (new Edge (edge .getFrom (), edge .getTo (), edge .getWeight ()));
37
38
this .graph .get (edge .getTo ()).add (new Edge (edge .getTo (), edge .getFrom (), edge .getWeight ()));
38
39
}
39
40
}
40
41
42
+ /**
43
+ * Represents an edge in the graph with a start node, end node, and weight.
44
+ */
41
45
private static class Edge {
42
-
43
46
private int from ;
44
47
private int to ;
45
48
private int weight ;
@@ -63,12 +66,13 @@ public int getWeight() {
63
66
}
64
67
}
65
68
66
- // class to iterate during the algorithm execution, and also used to return the solution.
67
- private static class PathAndDistance {
68
-
69
- private int distance ; // distance advanced so far.
70
- private ArrayList <Integer > path ; // list of visited nodes in this path.
71
- private int estimated ; // heuristic value associated to the last node od the path (current node).
69
+ /**
70
+ * Contains information about the path and its total distance.
71
+ */
72
+ static class PathAndDistance {
73
+ private int distance ; // total distance from the start node
74
+ private ArrayList <Integer > path ; // list of nodes in the path
75
+ private int estimated ; // heuristic estimate for reaching the destination
72
76
73
77
PathAndDistance (int distance , ArrayList <Integer > path , int estimated ) {
74
78
this .distance = distance ;
@@ -87,112 +91,54 @@ public ArrayList<Integer> getPath() {
87
91
public int getEstimated () {
88
92
return estimated ;
89
93
}
90
-
91
- private void printSolution () {
92
- if (this .path != null ) {
93
- System .out .println ("Optimal path: " + this .path + ", distance: " + this .distance );
94
- } else {
95
- System .out .println ("There is no path available to connect the points" );
96
- }
97
- }
98
94
}
99
95
100
- private static void initializeGraph (Graph graph , ArrayList <Integer > data ) {
96
+ // Initializes the graph with edges defined in the input data
97
+ static void initializeGraph (Graph graph , ArrayList <Integer > data ) {
101
98
for (int i = 0 ; i < data .size (); i += 4 ) {
102
99
graph .addEdge (new Edge (data .get (i ), data .get (i + 1 ), data .get (i + 2 )));
103
100
}
104
- /*
105
- .x. node
106
- (y) cost
107
- - or | or / bidirectional connection
108
-
109
- ( 98)- .7. -(86)- .4.
110
- |
111
- ( 85)- .17. -(142)- .18. -(92)- .8. -(87)- .11.
112
- |
113
- . 1. -------------------- (160)
114
- | \ |
115
- (211) \ .6.
116
- | \ |
117
- . 5. (101)-.13. -(138) (115)
118
- | | | /
119
- ( 99) ( 97) | /
120
- | | | /
121
- .12. -(151)- .15. -(80)- .14. | /
122
- | | | | /
123
- ( 71) (140) (146)- .2. -(120)
124
- | | |
125
- .19. -( 75)- . 0. .10. -(75)- .3.
126
- | |
127
- (118) ( 70)
128
- | |
129
- .16. -(111)- .9.
130
- */
131
- }
132
-
133
- public static void main (String [] args ) {
134
- // heuristic function optimistic values
135
- int [] heuristic = {
136
- 366 ,
137
- 0 ,
138
- 160 ,
139
- 242 ,
140
- 161 ,
141
- 178 ,
142
- 77 ,
143
- 151 ,
144
- 226 ,
145
- 244 ,
146
- 241 ,
147
- 234 ,
148
- 380 ,
149
- 98 ,
150
- 193 ,
151
- 253 ,
152
- 329 ,
153
- 80 ,
154
- 199 ,
155
- 374 ,
156
- };
157
-
158
- Graph graph = new Graph (20 );
159
- ArrayList <Integer > graphData = new ArrayList <>(Arrays .asList (0 , 19 , 75 , null , 0 , 15 , 140 , null , 0 , 16 , 118 , null , 19 , 12 , 71 , null , 12 , 15 , 151 , null , 16 , 9 , 111 , null , 9 , 10 , 70 , null , 10 , 3 , 75 , null , 3 , 2 , 120 , null , 2 , 14 , 146 , null , 2 , 13 , 138 , null , 2 , 6 , 115 , null , 15 , 14 , 80 , null ,
160
- 15 , 5 , 99 , null , 14 , 13 , 97 , null , 5 , 1 , 211 , null , 13 , 1 , 101 , null , 6 , 1 , 160 , null , 1 , 17 , 85 , null , 17 , 7 , 98 , null , 7 , 4 , 86 , null , 17 , 18 , 142 , null , 18 , 8 , 92 , null , 8 , 11 , 87 ));
161
- initializeGraph (graph , graphData );
162
-
163
- PathAndDistance solution = aStar (3 , 1 , graph , heuristic );
164
- solution .printSolution ();
165
101
}
166
102
103
+ /**
104
+ * Implements the A* pathfinding algorithm to find the shortest path from a start node to a destination node.
105
+ *
106
+ * @param from the starting node
107
+ * @param to the destination node
108
+ * @param graph the graph representation of the problem
109
+ * @param heuristic the heuristic estimates for each node
110
+ * @return a PathAndDistance object containing the shortest path and its distance
111
+ */
167
112
public static PathAndDistance aStar (int from , int to , Graph graph , int [] heuristic ) {
168
- // nodes are prioritised by the less value of the current distance of their paths, and the
169
- // estimated value
170
- // given by the heuristic function to reach the destination point from the current point.
113
+ // PriorityQueue to explore nodes based on their distance and estimated cost to reach the destination
171
114
PriorityQueue <PathAndDistance > queue = new PriorityQueue <>(Comparator .comparingInt (a -> (a .getDistance () + a .getEstimated ())));
172
115
173
- // dummy data to start the algorithm from the beginning point
174
- queue .add (new PathAndDistance (0 , new ArrayList <>(List .of (from )), 0 ));
116
+ // Start with the initial node
117
+ queue .add (new PathAndDistance (0 , new ArrayList <>(List .of (from )), heuristic [ from ] ));
175
118
176
119
boolean solutionFound = false ;
177
120
PathAndDistance currentData = new PathAndDistance (-1 , null , -1 );
121
+
178
122
while (!queue .isEmpty () && !solutionFound ) {
179
- currentData = queue .poll (); // first in the queue, best node so keep exploring.
180
- int currentPosition = currentData .getPath ().get (currentData .getPath ().size () - 1 ); // current node.
123
+ currentData = queue .poll (); // get the best node from the queue
124
+ int currentPosition = currentData .getPath ().get (currentData .getPath ().size () - 1 ); // current node
125
+
126
+ // Check if the destination has been reached
181
127
if (currentPosition == to ) {
182
128
solutionFound = true ;
183
129
} else {
184
130
for (Edge edge : graph .getNeighbours (currentPosition )) {
185
- if (!currentData .getPath ().contains (edge .getTo ())) { // Avoid Cycles
131
+ // Avoid cycles by checking if the next node is already in the path
132
+ if (!currentData .getPath ().contains (edge .getTo ())) {
186
133
ArrayList <Integer > updatedPath = new ArrayList <>(currentData .getPath ());
187
- updatedPath .add (edge .getTo ()); // Add the new node to the path, update the distance,
188
- // and the heuristic function value associated to that path.
134
+ updatedPath .add (edge .getTo ());
135
+
136
+ // Update the distance and heuristic for the new path
189
137
queue .add (new PathAndDistance (currentData .getDistance () + edge .getWeight (), updatedPath , heuristic [edge .getTo ()]));
190
138
}
191
139
}
192
140
}
193
141
}
194
142
return (solutionFound ) ? currentData : new PathAndDistance (-1 , null , -1 );
195
- // Out of while loop, if there is a solution, the current Data stores the optimal path, and
196
- // its distance
197
143
}
198
144
}
0 commit comments