Interactive Graph Theory Learning
Interactive Graph Theory Learning
Guest User
Using app without sign in
Interactive A* pathfinding visualizer
Finds the shortest path faster than Dijkstra by steering the search with a heuristic
Select an algorithm and generate steps to begin visualization
A* (pronounced "A star") finds the cheapest path between two points in a weighted graph, and it is the algorithm behind most game and robot pathfinding. It is Dijkstra with one addition: an estimate of how far each node still is from the goal, which lets the search push towards the destination instead of spreading out in every direction. Hart, Nilsson and Raphael published it in 1968.
Every node carries three numbers: g, the confirmed cost from the start; h, the estimated cost still to go; and f = g + h, the estimated total. A* keeps an open set of discovered nodes and always expands the one with the smallest f. Expanding a node means moving it to the closed set and relaxing its edges exactly as Dijkstra would. The search stops the moment the goal is expanded. With a binary heap this runs in O((V + E) log V), the same bound as Dijkstra, but it usually touches far fewer nodes.
A* is the default pathfinder in game engines, warehouse robots and drone navigation, and it drives route planning where a straight-line distance is available as a lower bound. It also solves sliding puzzles and other state-space searches where a good heuristic exists. In interviews it is the natural follow-up once a candidate has explained Dijkstra: the question is usually what property the heuristic needs for the answer to stay optimal.
A* is Dijkstra with one extra term. Where Dijkstra always expands the node with the smallest confirmed cost g, A* expands the one with the smallest f = g + h, where h estimates the cost still to go. Set h to zero everywhere and the pseudocode below becomes Dijkstra exactly.
A*(graph, start, goal, h):
for each vertex v: g[v] = infinity
g[start] = 0
f[start] = h(start)
open = priority queue containing (f[start], start)
closed = empty set
while open is not empty:
u = open.extractMin() // smallest f
if u == goal: return reconstruct(u)
add u to closed
for each edge (u, v, w):
if v in closed: continue
tentative = g[u] + w
if tentative < g[v]:
previous[v] = u
g[v] = tentative
f[v] = tentative + h(v)
open.insert(f[v], v)
return no pathThe closed-set skip on line 15 is only safe when h is consistent, meaning h(u) <= w(u, v) + h(v) for every edge. With a merely admissible heuristic you must allow nodes to leave the closed set and be reopened, or A* can return a suboptimal path. The visualizer above scales straight-line distance by the cheapest cost-per-unit any edge offers, which makes h consistent by the triangle inequality, so no reopening is needed.
Five nodes, with S at the origin and the goal G five units to its right. The point of the trace is the node A* never touches.
Example graph: S(0,0), A(2,1), B(2,-1), C(1,4), G(5,0). Edges S-A = 3, S-B = 2, S-C = 4, A-B = 2, A-G = 4, B-G = 6, C-G = 7. Scaling straight-line distance by the cheapest cost-per-unit on any edge (0.894) gives h(S) = 4.47, h(A) = 2.83, h(B) = 2.83, h(C) = 5.06, h(G) = 0.
A* returns S to A to G at a cost of 7, having expanded 4 nodes. Dijkstra on the same graph returns the identical path at the identical cost, but expands 5: it works through C before it is willing to settle the goal. C was never worth visiting, and h is what let A* know that without checking.
Time: O((V + E) log V) worst case with a binary heap · Space: O(V)
The worst case is Dijkstra's, and for the same reason: every vertex can enter the priority queue once and every edge can trigger one decrease-key, giving V extractions and E updates at O(log V) each. The heuristic changes none of that bound. What it changes is the constant: nodes whose f exceeds the goal's final cost are never expanded at all. With h = 0 A* degenerates to Dijkstra exactly; with a perfect h it walks straight down the optimal path expanding only its vertices. Across 4000 randomly generated weighted graphs, the implementation above expanded 4.58 nodes on average against Dijkstra's 5.52, and returned the optimal cost every single time.
A* is worth its extra machinery only when you have a goal and a usable estimate of the distance to it. Without either, one of these is the better tool.
| Alternative | Prefer it when | Cost |
|---|---|---|
| Dijkstra's algorithm | You need shortest paths to every node, or you have no meaningful heuristic. A* with h = 0 is exactly this. | O((V + E) log V) |
| Breadth-first search | Every edge costs the same. BFS finds the same answer with no priority queue at all. | O(V + E) |
| Bellman-Ford | Some edge weights are negative. A* inherits Dijkstra's non-negative assumption and breaks here. | O(V * E) |
| Bidirectional A* | Very large graphs with a single start and goal. Searching from both ends roughly halves the explored region. | O((V + E) log V) |
| Weighted A* (f = g + w*h) | You will trade optimality for speed. w > 1 finds paths faster but only guarantees costs within a factor w of optimal. | O((V + E) log V) |
Read the full article: A* Search Algorithm: Step-by-Step Guide
Read the full article: A* Search Algorithm in AI: The Complete Guide
Related algorithms: Dijkstra's Algorithm, Breadth-First Search, Bellman-Ford Algorithm