11package com .thealgorithms .graph ;
22
33import java .util .ArrayList ;
4- import java .util .Collections ;
54import java .util .HashMap ;
6- import java .util .HashSet ;
75import java .util .List ;
86import java .util .Map ;
97import java .util .PriorityQueue ;
10- import java .util .Scanner ;
118import java .util .Set ;
9+ import java .util .HashSet ;
10+ import java .util .Collections ;
1211
1312/**
14- * A* Search Algorithm for shortest pathfinding.
13+ * Implementation of the A* Search Algorithm for shortest pathfinding.
14+ *
15+ * <p>
16+ * A* combines Dijkstra’s algorithm with a heuristic to efficiently find the
17+ * shortest path in weighted graphs.
18+ * </p>
19+ *
20+ * <p>
21+ * Reference: https://en.wikipedia.org/wiki/A*_search_algorithm
22+ * </p>
1523 *
16- * <p>Commonly used in games, navigation, and robotics.
17- * Combines Dijkstra’s Algorithm and heuristic estimation.</p>
24+ * <p>
25+ * Time Complexity: O(E + V log V) with a binary heap priority queue.<br>
26+ * Space Complexity: O(V + E).
27+ * </p>
1828 *
19- * <p>Reference: https://en.wikipedia.org/wiki/A*_search_algorithm</p>
29+ * <p>
30+ * Usage is intended programmatically via the {@link Graph} and {@link #findPath}
31+ * method; interactive input should be handled externally or via tests.
32+ * </p>
2033 */
2134public class AStarSearch {
2235
23- static class Node implements Comparable <Node > {
24- int id ;
25- double g ; // Cost from start
26- double h ; // Heuristic to goal
27- double f ; // Total cost = g + h
28- Node parent ;
36+ /**
37+ * Represents a weighted directed graph using adjacency lists.
38+ */
39+ public static class Graph {
40+ private final Map <Integer , List <int []>> adjacencyList ;
41+
42+ /**
43+ * Constructs an empty graph.
44+ */
45+ public Graph () {
46+ adjacencyList = new HashMap <>();
47+ }
48+
49+ /**
50+ * Adds an undirected edge between nodes {@code u} and {@code v} with a weight.
51+ *
52+ * @param u first node
53+ * @param v second node
54+ * @param weight weight of the edge
55+ */
56+ public void addEdge (int u , int v , int weight ) {
57+ adjacencyList .computeIfAbsent (u , k -> new ArrayList <>()).add (new int [] { v , weight });
58+ adjacencyList .computeIfAbsent (v , k -> new ArrayList <>()).add (new int [] { u , weight });
59+ }
60+
61+ /**
62+ * Returns the adjacency list for a node.
63+ *
64+ * @param node node index
65+ * @return list of int[] {neighbor, weight}
66+ */
67+ public List <int []> getEdges (int node ) {
68+ return adjacencyList .getOrDefault (node , Collections .emptyList ());
69+ }
70+
71+ /**
72+ * Returns all nodes in the graph.
73+ *
74+ * @return set of node indices
75+ */
76+ public Set <Integer > getNodes () {
77+ return adjacencyList .keySet ();
78+ }
79+ }
80+
81+ /**
82+ * Node used in the priority queue for A*.
83+ */
84+ private static class Node implements Comparable <Node > {
85+ final int id ;
86+ final double g ; // cost from start
87+ final double h ; // heuristic
88+ final double f ; // total = g + h
89+ final Node parent ;
2990
3091 Node (int id , double g , double h , Node parent ) {
3192 this .id = id ;
@@ -41,33 +102,23 @@ public int compareTo(Node o) {
41102 }
42103 }
43104
44- private final Map <Integer , List <int []>> graph ;
45-
46- public AStarSearch () {
47- graph = new HashMap <>();
48- }
105+ private final Graph graph ;
49106
50107 /**
51- * Adds an undirected edge between nodes u and v with the given weight.
52- */
53- public void addEdge (int u , int v , int weight ) {
54- graph .computeIfAbsent (u , k -> new ArrayList <>()).add (new int []{v , weight });
55- graph .computeIfAbsent (v , k -> new ArrayList <>()).add (new int []{u , weight });
56- }
57-
58- /**
59- * Heuristic function (simplified for numeric nodes).
108+ * Constructs an A* solver for a given graph.
109+ *
110+ * @param graph weighted graph
60111 */
61- private double heuristic ( int node , int goal ) {
62- return Math . abs ( goal - node ) ;
112+ public AStarSearch ( Graph graph ) {
113+ this . graph = graph ;
63114 }
64115
65116 /**
66- * Finds the shortest path from start to goal using A* algorithm .
117+ * Finds the shortest path from {@code start} to {@code goal} using A* search .
67118 *
68119 * @param start starting node
69120 * @param goal goal node
70- * @return list of nodes representing the shortest path
121+ * @return list of nodes representing the shortest path, empty if none
71122 */
72123 public List <Integer > findPath (int start , int goal ) {
73124 PriorityQueue <Node > openSet = new PriorityQueue <>();
@@ -86,26 +137,38 @@ public List<Integer> findPath(int start, int goal) {
86137
87138 closedSet .add (current .id );
88139
89- for (int [] edge : graph .getOrDefault (current .id , Collections . emptyList () )) {
140+ for (int [] edge : graph .getEdges (current .id )) {
90141 int neighbor = edge [0 ];
91142 double tentativeG = current .g + edge [1 ];
92143
93- if (closedSet .contains (neighbor )) {
94- continue ;
95- }
144+ if (closedSet .contains (neighbor )) continue ;
96145
97146 if (tentativeG < gScore .getOrDefault (neighbor , Double .MAX_VALUE )) {
98147 gScore .put (neighbor , tentativeG );
99- Node next = new Node (neighbor , tentativeG , heuristic (neighbor , goal ), current );
100- openSet .add (next );
148+ openSet .add (new Node (neighbor , tentativeG , heuristic (neighbor , goal ), current ));
101149 }
102150 }
103151 }
152+
104153 return Collections .emptyList ();
105154 }
106155
107156 /**
108- * Reconstructs path by following parent nodes.
157+ * Simple heuristic: absolute difference between node indices.
158+ *
159+ * @param node current node
160+ * @param goal goal node
161+ * @return heuristic value
162+ */
163+ private double heuristic (int node , int goal ) {
164+ return Math .abs (goal - node );
165+ }
166+
167+ /**
168+ * Reconstructs the path from goal to start following parent links.
169+ *
170+ * @param node end node
171+ * @return list of node indices from start to goal
109172 */
110173 private List <Integer > reconstructPath (Node node ) {
111174 List <Integer > path = new ArrayList <>();
@@ -116,37 +179,4 @@ private List<Integer> reconstructPath(Node node) {
116179 Collections .reverse (path );
117180 return path ;
118181 }
119-
120- /**
121- * Dynamic usage: reads graph and start/goal from input.
122- */
123- public static void main (String [] args ) {
124- Scanner sc = new Scanner (System .in );
125- AStarSearch aStar = new AStarSearch ();
126-
127- System .out .print ("Enter number of edges: " );
128- int edges = sc .nextInt ();
129-
130- System .out .println ("Enter edges in format: u v weight" );
131- for (int i = 0 ; i < edges ; i ++) {
132- int u = sc .nextInt ();
133- int v = sc .nextInt ();
134- int w = sc .nextInt ();
135- aStar .addEdge (u , v , w );
136- }
137-
138- System .out .print ("Enter start node: " );
139- int start = sc .nextInt ();
140-
141- System .out .print ("Enter goal node: " );
142- int goal = sc .nextInt ();
143-
144- List <Integer > path = aStar .findPath (start , goal );
145- if (path .isEmpty ()) {
146- System .out .println ("No path found from " + start + " → " + goal );
147- } else {
148- System .out .println ("Shortest path from " + start + " → " + goal + ": " + path );
149- }
150- sc .close ();
151- }
152182}
0 commit comments