11package com .thealgorithms .graph ;
22
33import java .util .ArrayList ;
4+ import java .util .Collections ;
45import java .util .HashMap ;
6+ import java .util .HashSet ;
57import java .util .List ;
68import java .util .Map ;
79import java .util .PriorityQueue ;
810import java .util .Set ;
9- import java .util .HashSet ;
10- import java .util .Collections ;
11+ import java .util .Scanner ;
1112
1213/**
1314 * Implementation of the A* Search Algorithm for shortest pathfinding.
2324 *
2425 * <p>
2526 * Time Complexity: O(E + V log V) with a binary heap priority queue.<br>
26- * Space Complexity: O(V + E).
27- * </p>
28- *
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.
27+ * Space Complexity: O(V + E)
3228 * </p>
3329 */
3430public class AStarSearch {
3531
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- */
8432 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 ;
33+ int id ;
34+ double g ; // cost from start
35+ double h ; // heuristic to goal
36+ double f ; // total cost = g + h
37+ Node parent ;
9038
9139 Node (int id , double g , double h , Node parent ) {
9240 this .id = id ;
@@ -97,28 +45,47 @@ private static class Node implements Comparable<Node> {
9745 }
9846
9947 @ Override
100- public int compareTo (Node o ) {
101- return Double .compare (this .f , o .f );
48+ public int compareTo (Node other ) {
49+ return Double .compare (this .f , other .f );
10250 }
10351 }
10452
105- private final Graph graph ;
53+ private final Map <Integer , List <int []>> graph ;
54+
55+ /** Constructs an empty graph. */
56+ public AStarSearch () {
57+ graph = new HashMap <>();
58+ }
59+
60+ /**
61+ * Adds an undirected edge between nodes u and v with the given weight.
62+ *
63+ * @param u first node
64+ * @param v second node
65+ * @param weight edge weight
66+ */
67+ public void addEdge (int u , int v , int weight ) {
68+ graph .computeIfAbsent (u , k -> new ArrayList <>()).add (new int []{v , weight });
69+ graph .computeIfAbsent (v , k -> new ArrayList <>()).add (new int []{u , weight });
70+ }
10671
10772 /**
108- * Constructs an A* solver for a given graph .
73+ * Heuristic function for A* (simplified as absolute difference) .
10974 *
110- * @param graph weighted graph
75+ * @param node current node
76+ * @param goal goal node
77+ * @return heuristic estimate
11178 */
112- public AStarSearch ( Graph graph ) {
113- this . graph = graph ;
79+ private double heuristic ( int node , int goal ) {
80+ return Math . abs ( goal - node ) ;
11481 }
11582
11683 /**
117- * Finds the shortest path from {@code start} to {@code goal} using A* search .
84+ * Finds the shortest path from start to goal using A* algorithm .
11885 *
119- * @param start starting node
120- * @param goal goal node
121- * @return list of nodes representing the shortest path, empty if none
86+ * @param start start node
87+ * @param goal goal node
88+ * @return list of nodes representing the shortest path
12289 */
12390 public List <Integer > findPath (int start , int goal ) {
12491 PriorityQueue <Node > openSet = new PriorityQueue <>();
@@ -130,45 +97,32 @@ public List<Integer> findPath(int start, int goal) {
13097
13198 while (!openSet .isEmpty ()) {
13299 Node current = openSet .poll ();
133-
134100 if (current .id == goal ) {
135101 return reconstructPath (current );
136102 }
137103
138104 closedSet .add (current .id );
139-
140- for (int [] edge : graph .getEdges (current .id )) {
105+ for (int [] edge : graph .getOrDefault (current .id , new ArrayList <>())) {
141106 int neighbor = edge [0 ];
142107 double tentativeG = current .g + edge [1 ];
143-
144- if (closedSet .contains (neighbor )) continue ;
108+ if (closedSet .contains (neighbor )) {
109+ continue ;
110+ }
145111
146112 if (tentativeG < gScore .getOrDefault (neighbor , Double .MAX_VALUE )) {
147113 gScore .put (neighbor , tentativeG );
148114 openSet .add (new Node (neighbor , tentativeG , heuristic (neighbor , goal ), current ));
149115 }
150116 }
151117 }
152-
153118 return Collections .emptyList ();
154119 }
155120
156121 /**
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.
122+ * Reconstructs the path by following parent nodes.
169123 *
170124 * @param node end node
171- * @return list of node indices from start to goal
125+ * @return path from start to end
172126 */
173127 private List <Integer > reconstructPath (Node node ) {
174128 List <Integer > path = new ArrayList <>();
@@ -179,4 +133,33 @@ private List<Integer> reconstructPath(Node node) {
179133 Collections .reverse (path );
180134 return path ;
181135 }
136+
137+ /** Reads input dynamically and runs A* algorithm. */
138+ public static void main (String [] args ) {
139+ Scanner sc = new Scanner (System .in );
140+ AStarSearch aStar = new AStarSearch ();
141+
142+ System .out .print ("Enter number of edges: " );
143+ int edges = sc .nextInt ();
144+ System .out .println ("Enter edges in format: u v weight" );
145+ for (int i = 0 ; i < edges ; i ++) {
146+ int u = sc .nextInt ();
147+ int v = sc .nextInt ();
148+ int w = sc .nextInt ();
149+ aStar .addEdge (u , v , w );
150+ }
151+
152+ System .out .print ("Enter start node: " );
153+ int start = sc .nextInt ();
154+ System .out .print ("Enter goal node: " );
155+ int goal = sc .nextInt ();
156+
157+ List <Integer > path = aStar .findPath (start , goal );
158+ if (path .isEmpty ()) {
159+ System .out .println ("No path found from " + start + " → " + goal );
160+ } else {
161+ System .out .println ("Shortest path from " + start + " → " + goal + ": " + path );
162+ }
163+ sc .close ();
164+ }
182165}
0 commit comments