SysDesignPrep.com
Interactive concepts

Dijkstra vs A* route planning: an interactive shortest path visualizer

Route planning is a shortest-path search on a graph: intersections are nodes, road segments are edges weighted by travel time. Dijkstra’s algorithm finds the fastest route by exploring outward in order of travel time. A* finds the same route while exploring far less, by steering towards the goal with an estimate of the time left. Real map services go further and precompute shortcuts, so a cross-continent query touches only a few hundred nodes.

The playground plans the same trip three ways on a city grid with a river and a congested zone. Pick a trip or click the map to move the start and goal.

Click the map to move the

A 26 by 16 grid of 365 intersections; a block takes 1 minute, or 4 in the congested zone. All three find the same 31-minute route. Dijkstra explores 338 intersections: everything closer to the start than the goal is, in every direction. A*, steering by the straight-line distance still to go, explores 111, 33% as many. Searching from both ends at once explores 322.

Dijkstraexplores outward in every direction
Explored
338 of 365
Route
31 min
A*adds an estimate of the distance left
Explored
111 of 365
Route
31 min
Bidirectionalsearches from both ends until they meet
Explored
322 of 365
Route
31 min
startgoalexploredcongested, 4 min a blockbuildings and river

Dijkstra, A* and bidirectional search

Dijkstra expands intersections in order of their travel time from the start, so before it reaches a goal 30 minutes away it has visited everything closer than 30 minutes in every direction: 338 of the grid’s intersections for the trip across the river. A* orders them by time so far plus an estimate of the time left, here the straight-line distance in blocks, and visits 111. The estimate must never overestimate, or A* can miss the best route; on real roads it is the straight-line distance divided by the highest speed limit. Searching from both ends at once, which is how many production routers start, meets in the middle and on large road networks visits roughly half as much as one-directional Dijkstra.

The estimate helps most when the route is roughly a straight line: 7 intersections instead of 49 for a short trip. From corner to corner of the grid, nearly every intersection is on some plausible route, and A* visits 333 against Dijkstra’s 365.

How map services answer in milliseconds

A continental road graph has tens of millions of nodes, and even A* is too slow for millions of queries. Production routers precompute. Contraction hierarchies rank nodes by importance and add shortcut edges that skip unimportant ones, so a query only ever climbs to important roads and back down, touching hundreds of nodes. Customizable variants split the graph into cells and precompute paths across each cell, so live traffic can update edge weights every few minutes without redoing the whole preprocessing. Travel times themselves come from historical speeds per road segment and time of day, corrected by live probe data from phones and vehicles.

A* in code

import heapq

def a_star(graph, start, goal, h):
    """graph[n] -> [(neighbour, minutes)]; h(n) must never overestimate the minutes left."""
    best = {start: 0}
    came_from = {}
    frontier = [(h(start), start)]
    while frontier:
        _, node = heapq.heappop(frontier)
        if node == goal:
            break
        for nxt, minutes in graph[node]:
            cost = best[node] + minutes
            if cost < best.get(nxt, float("inf")):
                best[nxt], came_from[nxt] = cost, node
                heapq.heappush(frontier, (cost + h(nxt), nxt))   # h = 0 gives Dijkstra
    path = [goal]
    while path[-1] != start:
        path.append(came_from[path[-1]])
    return best[goal], path[::-1]

In a system design interview

For a maps or ride-hailing design, separate the graph from the queries: “The road graph is partitioned into cells and preprocessed offline into a multi-level overlay. Live traffic updates edge weights per cell every few minutes. A routing query runs a bidirectional search over the overlay, so it touches a few thousand nodes and returns in tens of milliseconds; ETAs come from the same weights, adjusted by a model trained on completed trips.” Expect the follow-ups: turn restrictions, alternative routes, and how traffic data is collected and smoothed.

Read the guide to routing and shortest paths or large-scale graph processing, see geohashes for finding the nearest road, or watch a strong candidate design Google Maps.

Questions people ask

How does Dijkstra’s algorithm work?

It keeps a priority queue of nodes ordered by the best known distance from the start, repeatedly takes the closest unvisited node, and relaxes its edges, updating neighbours whose distance improves. When the goal is taken from the queue, its distance is the shortest possible, as long as no edge has negative weight.

What is the difference between Dijkstra and A*?

A* orders the queue by the distance so far plus an estimate of the distance remaining, which steers the search towards the goal. With an estimate that never overestimates, such as straight-line distance divided by the top speed, A* finds the same shortest path while exploring far fewer nodes.

What makes an A* heuristic admissible?

It must never overestimate the true remaining cost. On a road network with travel times, the straight-line distance divided by the highest possible speed is admissible. An overestimating heuristic can make A* return a route that is not the fastest.

What is bidirectional search?

Running the search from the start and from the goal at the same time and stopping when the two frontiers meet with no better connection possible. On large, roughly uniform graphs it explores about half as many nodes as a one-directional search, and it is the basis of most fast routing algorithms.

How does Google Maps compute routes so fast?

By preprocessing the road graph. Techniques such as contraction hierarchies and multi-level overlay graphs add shortcut edges or precomputed cell-to-cell paths, so a query only searches a small number of important nodes. Customizable variants let live traffic update weights without full reprocessing.

What are contraction hierarchies?

A preprocessing technique that orders nodes by importance and contracts them one by one, adding shortcut edges that preserve shortest-path distances. Queries then run a bidirectional search that only moves upward in the hierarchy, touching hundreds of nodes even on continental road networks.

How are travel times on roads estimated?

From historical speeds per road segment and time of day, updated with live data from phones and vehicles moving along the roads, and adjusted for turns and traffic signals. ETA models are then trained on completed trips to correct systematic errors.