diff --git a/src/main/java/com/thealgorithms/others/AStarSearch.java b/src/main/java/com/thealgorithms/others/AStarSearch.java
new file mode 100644
index 000000000000..013d597657f2
--- /dev/null
+++ b/src/main/java/com/thealgorithms/others/AStarSearch.java
@@ -0,0 +1,152 @@
+package com.thealgorithms.others;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.PriorityQueue;
+
+/**
+ * A* (A-Star) Search Algorithm implementation for finding the shortest path
+ * between two nodes in a graph.
+ *
+ *
This algorithm uses a heuristic to guide its search, making it more efficient
+ * than Dijkstra’s algorithm in many cases.
+ *
+ *
f(n) = g(n) + h(n)
+ * where:
+ * - g(n): cost from start node to current node
+ * - h(n): estimated cost from current node to goal (heuristic)
+ *
+ *
Time Complexity:
+ * - Worst case: O(E log V)
+ *
+ *
Space Complexity:
+ * - O(V)
+ *
+ *
Use Cases:
+ * - Pathfinding (maps, games)
+ * - AI planning
+ *
+ * @author Suraj Devatha
+ */
+public final class AStarSearch {
+
+ private AStarSearch() {
+ }
+
+ /**
+ * Finds shortest path using A*.
+ *
+ * @param graph adjacency list
+ * @param start start node
+ * @param goal goal node
+ * @param heuristic heuristic function
+ * @return list of nodes representing shortest path
+ */
+ public static List findPath(Map> graph, Node start, Node goal, Heuristic heuristic) {
+
+ Map gScore = new HashMap<>();
+ Map fScore = new HashMap<>();
+ Map cameFrom = new HashMap<>();
+
+ PriorityQueue openSet = new PriorityQueue<>(Comparator.comparingDouble(fScore::get));
+
+ gScore.put(start, 0.0);
+ fScore.put(start, heuristic.estimate(start, goal));
+
+ openSet.add(start);
+
+ while (!openSet.isEmpty()) {
+ Node current = openSet.poll();
+
+ if (current.equals(goal)) {
+ return reconstructPath(cameFrom, current);
+ }
+
+ for (Edge edge : graph.getOrDefault(current, Collections.emptyList())) {
+ Node neighbor = edge.target;
+ double tentativeG = gScore.get(current) + edge.cost;
+
+ if (tentativeG < gScore.getOrDefault(neighbor, Double.POSITIVE_INFINITY)) {
+ cameFrom.put(neighbor, current);
+ gScore.put(neighbor, tentativeG);
+ fScore.put(neighbor, tentativeG + heuristic.estimate(neighbor, goal));
+
+ if (!openSet.contains(neighbor)) {
+ openSet.add(neighbor);
+ }
+ }
+ }
+ }
+
+ return Collections.emptyList(); // No path found
+ }
+
+ /**
+ * Reconstructs path from goal to start.
+ */
+ private static List reconstructPath(Map cameFrom, Node current) {
+ List path = new ArrayList<>();
+ path.add(current);
+
+ while (cameFrom.containsKey(current)) {
+ current = cameFrom.get(current);
+ path.add(current);
+ }
+
+ Collections.reverse(path);
+ return path;
+ }
+
+ /**
+ * Heuristic interface (can plug different heuristics).
+ */
+ public interface Heuristic {
+ double estimate(Node current, Node goal);
+ }
+
+ /**
+ * Node class representing a vertex in the graph.
+ */
+ static class Node {
+ String id;
+
+ Node(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Node)) {
+ return false;
+ }
+ Node node = (Node) o;
+ return Objects.equals(id, node.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+ }
+
+ /**
+ * Edge class representing weighted connections.
+ */
+ static class Edge {
+ Node target;
+ double cost;
+
+ Edge(Node target, double cost) {
+ this.target = target;
+ this.cost = cost;
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/others/AStarSearchTest.java b/src/test/java/com/thealgorithms/others/AStarSearchTest.java
new file mode 100644
index 000000000000..62debd27a165
--- /dev/null
+++ b/src/test/java/com/thealgorithms/others/AStarSearchTest.java
@@ -0,0 +1,116 @@
+package com.thealgorithms.others;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test cases for AStarSearch algorithm.
+ */
+class AStarSearchTest {
+
+ /**
+ * Simple heuristic that returns 0 (reduces A* to Dijkstra).
+ */
+ private static final AStarSearch.Heuristic ZERO_HEURISTIC = (node, goal) -> 0;
+ private static Map> graph;
+
+ private static AStarSearch.Node nodeA;
+ private static AStarSearch.Node nodeB;
+ private static AStarSearch.Node nodeC;
+ private static AStarSearch.Node nodeD;
+
+ @BeforeAll
+ static void setUp() {
+ graph = new HashMap<>();
+
+ nodeA = new AStarSearch.Node("A");
+ nodeB = new AStarSearch.Node("B");
+ nodeC = new AStarSearch.Node("C");
+ nodeD = new AStarSearch.Node("D");
+
+ graph.put(nodeA, Arrays.asList(new AStarSearch.Edge(nodeB, 1), new AStarSearch.Edge(nodeC, 4)));
+
+ graph.put(nodeB, Arrays.asList(new AStarSearch.Edge(nodeC, 2), new AStarSearch.Edge(nodeD, 5)));
+
+ graph.put(nodeC, Arrays.asList(new AStarSearch.Edge(nodeD, 1)));
+
+ graph.put(nodeD, Collections.emptyList());
+ }
+
+ @Test
+ void testPathExists() {
+ List path = AStarSearch.findPath(graph, nodeA, nodeD, ZERO_HEURISTIC);
+
+ // Expected shortest path: A -> B -> C -> D
+ List expected = Arrays.asList(nodeA, nodeB, nodeC, nodeD);
+
+ assertEquals(expected, path);
+ }
+
+ @Test
+ void testDirectPath() {
+ List path = AStarSearch.findPath(graph, nodeA, nodeB, ZERO_HEURISTIC);
+
+ List expected = Arrays.asList(nodeA, nodeB);
+
+ assertEquals(expected, path);
+ }
+
+ @Test
+ void testStartEqualsGoal() {
+ List path = AStarSearch.findPath(graph, nodeA, nodeA, ZERO_HEURISTIC);
+
+ List expected = Collections.singletonList(nodeA);
+
+ assertEquals(expected, path);
+ }
+
+ @Test
+ void testNoPathExists() {
+ AStarSearch.Node nodeE = new AStarSearch.Node("nodeE");
+
+ List path = AStarSearch.findPath(graph, nodeE, nodeA, ZERO_HEURISTIC);
+
+ assertTrue(path.isEmpty());
+ }
+
+ @Test
+ void testPathCostOptimality() {
+ List path = AStarSearch.findPath(graph, nodeA, nodeD, ZERO_HEURISTIC);
+
+ // Calculate total cost
+ double cost = calculatePathCost(path);
+
+ // Expected shortest cost = 1 (A->B) + 2 (B->C) + 1 (C->D) = 4
+ assertEquals(4.0, cost);
+ }
+
+ /**
+ * Utility method to calculate path cost.
+ */
+ private double calculatePathCost(List path) {
+ double total = 0;
+
+ for (int i = 0; i < path.size() - 1; i++) {
+ AStarSearch.Node current = path.get(i);
+ AStarSearch.Node next = path.get(i + 1);
+
+ for (AStarSearch.Edge edge : graph.getOrDefault(current, Collections.emptyList())) {
+ if (edge.target.equals(next)) {
+ total += edge.cost;
+ break;
+ }
+ }
+ }
+
+ return total;
+ }
+}