Skip to content

Commit 1bd62d6

Browse files
authored
Update AStarSearch.java
1 parent 9a05c56 commit 1bd62d6

File tree

1 file changed

+116
-125
lines changed

1 file changed

+116
-125
lines changed

src/main/java/com/thealgorithms/graph/AStarSearch.java

Lines changed: 116 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -12,129 +12,120 @@
1212
*/
1313
public class AStarSearch {
1414

15-
static class Node implements Comparable<Node> {
16-
int id;
17-
double g; // Cost from start
18-
double h; // Heuristic to goal
19-
double f; // Total cost = g + h
20-
Node parent;
21-
22-
Node(int id, double g, double h, Node parent) {
23-
this.id = id;
24-
this.g = g;
25-
this.h = h;
26-
this.f = g + h;
27-
this.parent = parent;
28-
}
29-
30-
@Override
31-
public int compareTo(Node o) {
32-
return Double.compare(this.f, o.f);
33-
}
34-
}
35-
36-
private final Map<Integer, List<int[]>> graph;
37-
38-
public AStarSearch() {
39-
graph = new HashMap<>();
40-
}
41-
42-
/**
43-
* Adds an undirected edge between nodes u and v with the given weight.
44-
*/
45-
public void addEdge(int u, int v, int weight) {
46-
graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new int[]{v, weight});
47-
graph.computeIfAbsent(v, k -> new ArrayList<>()).add(new int[]{u, weight});
48-
}
49-
50-
/**
51-
* Heuristic function (simplified for numeric nodes).
52-
*/
53-
private double heuristic(int node, int goal) {
54-
return Math.abs(goal - node);
55-
}
56-
57-
/**
58-
* Finds the shortest path from start to goal using A* algorithm.
59-
*
60-
* @param start starting node
61-
* @param goal goal node
62-
* @return list of nodes representing the shortest path
63-
*/
64-
public List<Integer> findPath(int start, int goal) {
65-
PriorityQueue<Node> openSet = new PriorityQueue<>();
66-
Map<Integer, Double> gScore = new HashMap<>();
67-
Set<Integer> closedSet = new HashSet<>();
68-
69-
openSet.add(new Node(start, 0, heuristic(start, goal), null));
70-
gScore.put(start, 0.0);
71-
72-
while (!openSet.isEmpty()) {
73-
Node current = openSet.poll();
74-
75-
if (current.id == goal) {
76-
return reconstructPath(current);
77-
}
78-
79-
closedSet.add(current.id);
80-
81-
for (int[] edge : graph.getOrDefault(current.id, new ArrayList<>())) {
82-
int neighbor = edge[0];
83-
double tentativeG = current.g + edge[1];
84-
85-
if (closedSet.contains(neighbor)) continue;
86-
87-
if (tentativeG < gScore.getOrDefault(neighbor, Double.MAX_VALUE)) {
88-
gScore.put(neighbor, tentativeG);
89-
Node next = new Node(neighbor, tentativeG, heuristic(neighbor, goal), current);
90-
openSet.add(next);
91-
}
92-
}
93-
}
94-
return Collections.emptyList();
95-
}
96-
97-
/**
98-
* Reconstructs path by following parent nodes.
99-
*/
100-
private List<Integer> reconstructPath(Node node) {
101-
List<Integer> path = new ArrayList<>();
102-
while (node != null) {
103-
path.add(node.id);
104-
node = node.parent;
105-
}
106-
Collections.reverse(path);
107-
return path;
108-
}
109-
110-
/** Dynamic usage: reads graph and start/goal from input */
111-
public static void main(String[] args) {
112-
Scanner sc = new Scanner(System.in);
113-
AStarSearch aStar = new AStarSearch();
114-
115-
System.out.print("Enter number of edges: ");
116-
int edges = sc.nextInt();
117-
118-
System.out.println("Enter edges in format: u v weight");
119-
for (int i = 0; i < edges; i++) {
120-
int u = sc.nextInt();
121-
int v = sc.nextInt();
122-
int w = sc.nextInt();
123-
aStar.addEdge(u, v, w);
124-
}
125-
126-
System.out.print("Enter start node: ");
127-
int start = sc.nextInt();
128-
129-
System.out.print("Enter goal node: ");
130-
int goal = sc.nextInt();
131-
132-
List<Integer> path = aStar.findPath(start, goal);
133-
if (path.isEmpty()) {
134-
System.out.println("No path found from " + start + " → " + goal);
135-
} else {
136-
System.out.println("Shortest path from " + start + " → " + goal + ": " + path);
137-
}
138-
sc.close();
139-
}
15+
@FunctionalInterface
16+
public interface Heuristic {
17+
double estimate(int node, int goal);
18+
}
19+
20+
static class Node implements Comparable<Node> {
21+
int id;
22+
double g; // Cost from start
23+
double h; // Heuristic to goal
24+
double f; // Total cost = g + h
25+
Node parent;
26+
27+
Node(int id, double g, double h, Node parent) {
28+
this.id = id;
29+
this.g = g;
30+
this.h = h;
31+
this.f = g + h;
32+
this.parent = parent;
33+
}
34+
35+
@Override
36+
public int compareTo(Node o) {
37+
return Double.compare(this.f, o.f);
38+
}
39+
40+
@Override
41+
public boolean equals(Object o) {
42+
if (this == o) return true;
43+
if (!(o instanceof Node)) return false;
44+
Node node = (Node) o;
45+
return id == node.id;
46+
}
47+
48+
@Override
49+
public int hashCode() {
50+
return Objects.hash(id);
51+
}
52+
}
53+
54+
private final Map<Integer, List<int[]>> graph;
55+
private final Heuristic heuristic;
56+
57+
/**
58+
* Constructor with default heuristic (|goal - node|).
59+
*/
60+
public AStarSearch() {
61+
this.graph = new HashMap<>();
62+
this.heuristic = (node, goal) -> Math.abs(goal - node);
63+
}
64+
65+
/**
66+
* Constructor with custom heuristic.
67+
*/
68+
public AStarSearch(Heuristic heuristic) {
69+
this.graph = new HashMap<>();
70+
this.heuristic = heuristic;
71+
}
72+
73+
/**
74+
* Adds an undirected edge between nodes u and v with the given weight.
75+
*/
76+
public void addEdge(int u, int v, int weight) {
77+
graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new int[]{v, weight});
78+
graph.computeIfAbsent(v, k -> new ArrayList<>()).add(new int[]{u, weight});
79+
}
80+
81+
/**
82+
* Finds the shortest path from start to goal using A* algorithm.
83+
*
84+
* @param start starting node
85+
* @param goal goal node
86+
* @return list of nodes representing the shortest path
87+
*/
88+
public List<Integer> findPath(int start, int goal) {
89+
PriorityQueue<Node> openSet = new PriorityQueue<>();
90+
Map<Integer, Double> gScore = new HashMap<>();
91+
Set<Integer> closedSet = new HashSet<>();
92+
93+
openSet.add(new Node(start, 0, heuristic.estimate(start, goal), null));
94+
gScore.put(start, 0.0);
95+
96+
while (!openSet.isEmpty()) {
97+
Node current = openSet.poll();
98+
99+
if (current.id == goal) return reconstructPath(current);
100+
101+
closedSet.add(current.id);
102+
103+
for (int[] edge : graph.getOrDefault(current.id, new ArrayList<>())) {
104+
int neighbor = edge[0];
105+
double tentativeG = current.g + edge[1];
106+
107+
if (closedSet.contains(neighbor)) continue;
108+
109+
if (tentativeG < gScore.getOrDefault(neighbor, Double.MAX_VALUE)) {
110+
gScore.put(neighbor, tentativeG);
111+
Node next = new Node(neighbor, tentativeG, heuristic.estimate(neighbor, goal), current);
112+
openSet.add(next);
113+
}
114+
}
115+
}
116+
return Collections.emptyList();
117+
}
118+
119+
/**
120+
* Reconstructs path by following parent nodes.
121+
*/
122+
private List<Integer> reconstructPath(Node node) {
123+
List<Integer> path = new ArrayList<>();
124+
while (node != null) {
125+
path.add(node.id);
126+
node = node.parent;
127+
}
128+
Collections.reverse(path);
129+
return path;
130+
}
140131
}

0 commit comments

Comments
 (0)