Skip to content

Commit 8aec567

Browse files
authored
Update AStarSearch.java
1 parent e813c12 commit 8aec567

File tree

1 file changed

+101
-71
lines changed

1 file changed

+101
-71
lines changed
Lines changed: 101 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,92 @@
11
package com.thealgorithms.graph;
22

33
import java.util.ArrayList;
4-
import java.util.Collections;
54
import java.util.HashMap;
6-
import java.util.HashSet;
75
import java.util.List;
86
import java.util.Map;
97
import java.util.PriorityQueue;
10-
import java.util.Scanner;
118
import 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
*/
2134
public 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

Comments
 (0)