|
| 1 | +package com.thealgorithms.backtracking; |
| 2 | + |
| 3 | +// Author: Jivan Jamdar |
| 4 | + |
| 5 | +/* A* Search |
| 6 | + Problem : finds the shortest path between nodes in a weighted graph by combining actual travel costs and heuristic estimates. |
| 7 | +
|
| 8 | + Graph Structure: |
| 9 | +
|
| 10 | + (0) --1.0--> (1) --1.0--> (2) --1.0--> (3) --1.0--> (4) --1.0--> (5) |
| 11 | + Coordinates: |
| 12 | +
|
| 13 | + Node 0: (0, 0) |
| 14 | + Node 1: (1, 1) |
| 15 | + Node 2: (2, 2) |
| 16 | + Node 3: (3, 3) |
| 17 | + Node 4: (4, 4) |
| 18 | + Node 5: (5, 5) |
| 19 | +
|
| 20 | +finds the shortest path from Node 0 to Node 5 using the Euclidean distance as a heuristic. |
| 21 | +
|
| 22 | +Path Found: |
| 23 | +[0, 1, 2, 3, 4, 5] |
| 24 | +
|
| 25 | +*/ |
| 26 | + |
| 27 | +import java.util.ArrayList; |
| 28 | +import java.util.HashMap; |
| 29 | +import java.util.List; |
| 30 | +import java.util.Map; |
| 31 | +import java.util.PriorityQueue; |
| 32 | +import java.util.Comparator; |
| 33 | +import java.util.Collections; |
| 34 | + |
| 35 | +public class AStarSearch { |
| 36 | + |
| 37 | + // Helper class to represent graph edges |
| 38 | + static class Edge { |
| 39 | + int target; // Target vertex |
| 40 | + double weight; // Weight of the edge |
| 41 | + |
| 42 | + Edge(int target, double weight) { |
| 43 | + this.target = target; |
| 44 | + this.weight = weight; |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + // Helper class to represent a node with its fScore for the priority queue |
| 49 | + static class Node { |
| 50 | + int vertex; // Vertex index |
| 51 | + double fScore; // Total estimated cost |
| 52 | + |
| 53 | + Node(int vertex, double fScore) { |
| 54 | + this.vertex = vertex; |
| 55 | + this.fScore = fScore; |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + // Comparator for priority queue to prioritize based on fScore |
| 60 | + static class NodeComparator implements Comparator<Node> { |
| 61 | + public int compare(Node n1, Node n2) { |
| 62 | + return Double.compare(n1.fScore, n2.fScore); |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + // Heuristic function (Euclidean distance between two points as an example) |
| 67 | + public double heuristic(int[] point1, int[] point2) { |
| 68 | + return Math.sqrt(Math.pow(point1[0] - point2[0], 2) + Math.pow(point1[1] - point2[1], 2)); |
| 69 | + } |
| 70 | + |
| 71 | + // A* Search algorithm |
| 72 | + public List<Integer> aStar(List<List<Edge>> graph, int[] start, int[] goal, Map<Integer, int[]> coordinates) { |
| 73 | + int V = graph.size(); |
| 74 | + double[] gScore = new double[V]; |
| 75 | + Arrays.fill(gScore, Double.MAX_VALUE); |
| 76 | + gScore[start[0]] = 0; |
| 77 | + |
| 78 | + double[] fScore = new double[V]; // (g + heuristic) |
| 79 | + Arrays.fill(fScore, Double.MAX_VALUE); |
| 80 | + fScore[start[0]] = heuristic(coordinates.get(start[0]), coordinates.get(goal[0])); |
| 81 | + |
| 82 | + PriorityQueue<Node> openSet = new PriorityQueue<>(new NodeComparator()); |
| 83 | + openSet.add(new Node(start[0], fScore[start[0]])); |
| 84 | + |
| 85 | + Map<Integer, Integer> cameFrom = new HashMap<>(); |
| 86 | + |
| 87 | + while (!openSet.isEmpty()) { |
| 88 | + Node current = openSet.poll(); |
| 89 | + |
| 90 | + // Check if the goal has been reached |
| 91 | + if (current.vertex == goal[0]) { |
| 92 | + return reconstructPath(cameFrom, current.vertex); |
| 93 | + } |
| 94 | + |
| 95 | + // Explore neighbors |
| 96 | + for (Edge neighbor : graph.get(current.vertex)) { |
| 97 | + double tentative_gScore = gScore[current.vertex] + neighbor.weight; |
| 98 | + |
| 99 | + // If the new path is better, update the scores |
| 100 | + if (tentative_gScore < gScore[neighbor.target]) { |
| 101 | + cameFrom.put(neighbor.target, current.vertex); |
| 102 | + gScore[neighbor.target] = tentative_gScore; |
| 103 | + fScore[neighbor.target] = gScore[neighbor.target] + heuristic(coordinates.get(neighbor.target), coordinates.get(goal[0])); |
| 104 | + openSet.add(new Node(neighbor.target, fScore[neighbor.target])); |
| 105 | + } |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + return Collections.emptyList(); |
| 110 | + } |
| 111 | + |
| 112 | + // Helper method to reconstruct the path from start to goal |
| 113 | + private List<Integer> reconstructPath(Map<Integer, Integer> cameFrom, int current) { |
| 114 | + List<Integer> path = new ArrayList<>(); |
| 115 | + path.add(current); |
| 116 | + while (cameFrom.containsKey(current)) { |
| 117 | + current = cameFrom.get(current); |
| 118 | + path.add(current); |
| 119 | + } |
| 120 | + Collections.reverse(path); |
| 121 | + return path; |
| 122 | + } |
| 123 | +} |
0 commit comments