A Bit of History
A* was developed in 1968 by Peter Hart, Nils Nilsson, and Bertram Raphael at the Stanford Research Institute (SRI), as part of the Shakey project. Shakey the Robot, an early mobile robot able to reason about actions, needed to plan around obstacles using very limited computing resources. Their paper, "A Formal Basis for the Heuristic Determination of Minimum Cost Paths," did more than propose a faster search: it identified conditions under which heuristic guidance preserves optimality. That marriage of practical direction and a formal guarantee is why A* became a foundational tool in pathfinding and planning.
The Three Scores
For every discovered vertex $v$, A* separates what it knows from what it estimates:
Cost already paid
The cheapest start-to-$v$ path discovered so far. Edge relaxation can lower it.
Estimated cost remaining
A problem-specific lower bound—or optimistic guess—from $v$ to the goal.
Estimated total route
The priority-queue key. A* expands the frontier state with smallest $f$.
Working Principle
A* is best understood as Dijkstra's relaxation rule with a more informed queue order. Assume finite, nonnegative edge costs and a goal heuristic:
- Set $g(start)=0$ and push the start with priority $h(start)$.
- Pop the entry with minimum $f$. Skip it if its saved $g$ no longer equals the best known $g$ for that vertex.
- If it is the goal, reconstruct the path through parent pointers.
- For every edge $(u,v)$ of cost $w\ge 0$, relax $g(v)$ with $g(u)+w$. On improvement, update the parent and push a fresh queue entry.
- If the queue empties, the goal is unreachable.
Allowing a better $g$ value to push a vertex again is called reopening. It keeps graph-search A* correct for admissible heuristics even when they are inconsistent. Old heap entries are harmless because the stale-entry test discards them.
| Search | Priority | Behavior |
|---|---|---|
| Dijkstra | $g(v)$ | Uniformly expands cheapest known distance; equivalent to A* with $h=0$ |
| Greedy best-first | $h(v)$ | Aims at the goal but ignores cost already paid; not generally optimal |
| A* | $g(v)+h(v)$ | Balances evidence and guidance |
Choosing a Heuristic
Admissible: never overestimate
If $h^*(v)$ is the true cheapest remaining cost, admissibility requires $0\le h(v)\le h^*(v)$. The heuristic is optimistic: it may ignore walls, traffic, or terrain, but it cannot invent extra cost.
Consistent: obey a triangle inequality
For every edge $(u,v)$ with cost $w(u,v)$, consistency requires
$$h(u) \le w(u,v)+h(v), \qquad h(goal)=0.$$
Then $f$ never decreases along a path, so once a vertex is expanded with its best queue entry, it never needs reopening. Every consistent heuristic is admissible under the usual goal assumptions; an admissible heuristic need not be consistent.
| Movement model | Admissible heuristic | Formula for unit grid costs |
|---|---|---|
| 4 directions | Manhattan | $|\Delta x|+|\Delta y|$ |
| 8 directions; every move costs 1 | Chebyshev | $\max(|\Delta x|,|\Delta y|)$ |
| 8 directions; diagonal costs $\sqrt2$ | Octile | $\max(dx,dy)+(\sqrt2-1)\min(dx,dy)$ |
| Geometric movement | Euclidean | $\sqrt{(\Delta x)^2+(\Delta y)^2}$ |
Match the units. If one orthogonal step can cost as little as $c_{min}$, scale Manhattan distance by $c_{min}$. Obstacles may be ignored because ignoring them lowers the estimate. Discounted shortcuts, portals, or cheaper diagonal moves must be reflected or the heuristic may overestimate.
Stronger Without Overstepping
Among admissible heuristics, a larger estimate is usually more informative. If $h_1$ and $h_2$ are admissible, $\max(h_1,h_2)$ is also admissible and dominates either one. Multiplying by a factor greater than 1 may be faster, but gives up ordinary A*'s optimality guarantee.
Worked Example
Use a 7×5 grid with unit-cost four-directional movement. Start at $(0,2)$, goal at $(6,2)$, and place a vertical wall in column 3 with one opening at the bottom. Manhattan distance ignores the wall, so it begins at 6 even though the true route cost is 10.
The early $f=6$ values are lower bounds, not promises. When the search reaches the wall and must move away from the goal, $g$ rises faster than $h$ falls, revealing the true $f=10$ route cost.
Why A* Is Optimal
Assume nonnegative edges, $h(goal)=0$, an admissible heuristic, and an implementation that accepts improved $g$ values even for previously expanded vertices. Let $C^*$ be the optimal start-to-goal cost.
Before an optimal solution is found, some frontier vertex $x$ lies on an optimal path with its optimal prefix cost $g^*(x)$. Because $h$ never overestimates,
$$f(x)=g^*(x)+h(x)\le g^*(x)+h^*(x)=C^*.$$
If A* popped the goal with cost greater than $C^*$, that goal entry would have $f(goal)=g(goal)>C^*$ while $x$ still had priority at most $C^*$. A min-priority queue could not choose the goal first. Therefore the first non-stale goal entry has optimal cost.
What consistency buys you
For a consistent heuristic, every traversed edge satisfies $f(v)\ge f(u)$ after relaxation from $u$. Once a vertex is expanded at minimum $f$, no later route can improve its $g$ value. A permanent closed set is then safe. With an admissible but inconsistent heuristic, reopening may be necessary—the implementation below supports it.
How Overestimation Can Lose the Best Path
Suppose $S\to A\to G$ costs $2+2=4$, while $S\to B\to G$ costs $1+4=5$. If $h(A)=10$ and $h(B)=0$, A* may pop B and then G before considering A, returning cost 5. The inflated estimate hid the true optimum.
Complexity Analysis
With a consistent heuristic, nonnegative edges, and a binary heap, each vertex is expanded at most once and each edge is relaxed once:
$$\text{Time: } O((V+E)\log V) \qquad \text{Space: } O(V+E)$$
The duplicate-entry heap used below may hold multiple entries for a vertex, but at most one per successful relaxation; its logarithmic factor can be written $\log E$, which is $O(\log V)$ for ordinary simple graphs.
Heuristic quality mostly changes the number of states reached before the goal. With $h=0$, A* is Dijkstra. With a perfect heuristic, it can focus tightly on optimal routes. With an inconsistent heuristic, reopening can cause additional expansions and the simple one-expansion bound no longer applies.
Memory Is Often the Real Limit
A* retains frontier scores and parent information for many discovered states. On enormous implicit search spaces, memory can run out before asymptotic runtime becomes the practical bottleneck.
Implementation
The code uses duplicate heap entries instead of a decrease-key operation. Each entry remembers the $g$ value that created it; if a better route has since been found, the entry is stale and skipped.
| State | Meaning | Invariant |
|---|---|---|
g[v] | Best discovered start-to-$v$ cost | Only decreases after first discovery |
parent[v] | Predecessor achieving current g[v] | Following parents reconstructs the current best path |
heap entry (f,g,v) | Snapshot of one candidate | Process only when saved g == g[v] |
| edge weight | Real transition cost | Must be nonnegative for this A* contract |
Real-World Applications
A* is most useful when the state space is too large to search blindly, transitions have nonnegative costs, and the domain supplies a meaningful lower bound on the remaining cost.
Grid and navigation-mesh routing
A character can search cells, polygons, or waypoints. Distance to the destination guides the search, while terrain, doors, and hazards contribute to $g$.
Motion planning
A state may encode position, heading, or velocity—not just a point. A lower bound that ignores some constraints can still help because the relaxed problem is cheaper to solve.
Road and transit networks
Straight-line distance divided by a valid maximum speed can lower-bound travel time. Turn restrictions and real travel costs stay in the graph model.
Puzzles and action sequences
Board configurations or world states become vertices. Heuristics often come from a relaxed puzzle, pattern database, or count of unresolved constraints.
The graph is a modeling choice
Before tuning a heuristic, decide what one state means and which transitions are legal. A grid cell may be enough for a simple map; a car-like robot may need $(x,y,\theta)$ so orientation is part of the state. A* can only optimize paths represented by that model.
Variants & Tradeoffs
| Variant | Priority / idea | Why use it? | What changes? |
|---|---|---|---|
| Dijkstra | $f=g$ | No useful heuristic is available | Optimal with nonnegative edges, but explores more broadly |
| Weighted A* | $f=g+w h$, $w>1$ | Prefer a fast good route over the exact optimum | More goal-directed; ordinary optimality is deliberately surrendered |
| IDA* | Depth-first passes under increasing $f$ limits | Memory is the bottleneck | Small memory footprint, but repeated work |
| Bidirectional A* | Search from both ends | Long routes with useful forward and reverse heuristics | Meeting and stopping rules require care |
Think of the Heuristic as a Steering Signal
$g$ keeps the search honest; $h$ points it forward. Making $h$ more informative can reduce exploration without changing the answer, provided it stays admissible. Multiplying it above 1 pushes the steering harder and changes the problem from exact search to a speed–quality tradeoff.
Pitfalls & Debugging
| Symptom | Likely cause | Check or fix |
|---|---|---|
| A suboptimal route is returned | The heuristic overestimates, the goal was accepted when generated, or improved nodes were never reopened | Test $h(v)\le h^*(v)$ on small cases; stop only when a non-stale goal entry is popped; use the stale-entry pattern above |
| Too many states are expanded | The heuristic is weak or badly scaled | Compare the units and typical magnitude of $h$ with actual edge costs |
| Behavior changes across runs | Many states tie on $f$ | Add a deterministic secondary key; tie-breaking changes work performed, not optimal cost under the stated assumptions |
| The heap grows unexpectedly | Duplicate entries are normal, but stale entries may not be skipped | Store the pushed $g$ and compare it with current best $g[v]$ after every pop |
| The algorithm loops or gives nonsense | Negative edges, overflow, or invalid heuristic values | Reject negative weights; choose a safe numeric type; disallow NaN or infinity unless handled explicitly |
Do Not Stop When the Goal Is First Discovered
Generation proves only that one route reached the goal. Another frontier state may still lead to it more cheaply. The safe stopping point for the algorithm presented here is when the goal is removed from the priority queue through a non-stale entry.
Exercises
Build the Intuition in Layers
- Trace: Reproduce the worked grid by hand. Record the open set after each pop and state your tie-breaking rule.
- Compare: Repeat with $h=0$. Which extra cells does Dijkstra expand, and why?
- Reason: Prove Manhattan distance is consistent for four-direction moves of cost 1.
- Diagnose: Find an admissible but inconsistent heuristic on a four-vertex graph. Show where a permanent closed set can fail and how reopening repairs it.
- Engineer: Add counters for pops, stale entries, relaxations, and peak heap size to one implementation. Compare several heuristics on the same maps.
- Explore: Implement weighted A* with $w\in\{1,1.25,1.5,2\}$. Plot path cost against expanded states instead of judging speed from one run.
A compact mental model
A* is Dijkstra with informed ordering. The $g$ score records evidence, the heuristic supplies optimistic guidance, and $f=g+h$ decides what to investigate next. Correctness comes from the heuristic contract and from handling later improvements correctly—not from the priority formula alone.