Dijkstra explores outward evenly in every direction. When you know where the goal is, that's wasteful. A* adds a heuristic estimate of the remaining distance so the search leans toward the target.
Each node gets f(n) = g(n) + h(n): g is the known cost from the start, and h estimates the cost to the goal. A* always expands the node with the smallest f.
import heapq
def astar(start, goal, neighbors, h):
g = {start: 0}
pq = [(h(start), start)]
while pq:
f, u = heapq.heappop(pq)
if u == goal:
return g[u]
if f > g[u] + h(u):
continue # stale entry
for v, w in neighbors(u):
ng = g[u] + w
if ng < g.get(v, float("inf")):
g[v] = ng
heapq.heappush(pq, (ng + h(v), v))
return None
With h = 0, A* is exactly Dijkstra. With a perfect h, it walks straight to the goal.
|dx| + |dy|.Using Euclidean distance on a 4-directional grid is still admissible but weaker, so it expands more nodes; using Manhattan on an 8-directional grid overestimates and breaks optimality.
One-liner: "A* is Dijkstra ordered by g + h; with an admissible, consistent heuristic it stays optimal while exploring far fewer nodes."
Disclosure: from the team behind Linkjob AI interview copilot.