When a shortest-path algorithm reports only a distance, you can still recover the route by recording how each reached vertex was discovered. This guide shows how to add predecessor tracking to Dijkstra’s algorithm, then follow those links backward from the destination to rebuild the path.
What You’ll Need
- A weighted graph represented as an adjacency list or another structure your algorithm can inspect.
- A source vertex and a destination vertex.
- An implementation of Dijkstra’s algorithm, or a way to run it with nonnegative edge weights.
- A distance table and a predecessor table (also called a parent table) indexed by vertex.
Step-by-Step
- Confirm that Dijkstra’s algorithm applies. Its edge weights must be nonnegative. If your graph contains negative-weight edges, use an algorithm designed to handle them, such as Bellman–Ford, and apply the same predecessor idea when a distance improves. Decide whether the graph is directed or undirected; this determines which edges are available to traverse.
- Initialize distances and predecessors. Set the source distance to zero and every other vertex’s distance to infinity, meaning “not reached yet.” Set every predecessor to empty or null. For example, with source A, start with
dist[A] = 0,dist[B] = infinity, andprev[A] = prev[B] = null. - Run the normal shortest-distance search. Repeatedly select the unsettled vertex with the smallest tentative distance. With a priority queue, remove its smallest entry; ignore it if it is an outdated entry or the vertex has already been finalized. Examine each outgoing edge from that vertex.
- Update the predecessor whenever a distance improves. For an edge from
utovwith weightw, calculatecandidate = dist[u] + w. Ifcandidate < dist[v], set bothdist[v] = candidateandprev[v] = u. The predecessor assignment is essential: it records the last vertex on the newly best-known route tov. Do not update the predecessor when a candidate is worse. - Keep distance and predecessor updates together. Treat them as one logical operation. If you update the distance but forget its predecessor, the final distance may be correct while the route is incomplete or wrong. In a priority-queue implementation, push the improved distance as usual; the predecessor table does not replace the queue.
- Finish the search according to your goal. If you need paths to every reachable vertex, run until the queue is empty. If you need only one destination, you may stop once that destination is removed from the priority queue as the current smallest valid entry. Do not stop merely when it is first discovered: another route may still improve its distance.
- Check whether the destination is reachable. If its distance remains infinity, report that no route exists. Do not try to reconstruct a path from a null predecessor chain; the destination was never reached from the source.
- Walk backward from the destination. Start a result list with the destination. Repeatedly replace the current vertex with its predecessor and append that vertex, stopping when you reach the source. For example, if the links are
prev[D] = C,prev[C] = B, andprev[B] = A, the backward list is D, C, B, A. - Reverse the list and return it with the distance. Reverse the collected vertices to get A, B, C, D. The distance is still
dist[D]; the predecessor chain supplies the route, not a new distance calculation. If source and destination are the same, the path is just that single vertex and the distance is zero. - Verify the reconstructed route. Confirm that each consecutive pair is connected by an allowed edge and add those edge weights. The sum should equal the reported distance. This check can expose a direction mistake, an incorrect predecessor update, or a graph representation bug.
Common Mistakes
Recording a predecessor only the first time a vertex is found: a later route can be shorter. Replace the predecessor every time the distance strictly improves. Stopping when the destination is first encountered: discovery does not prove optimality; wait until it is finalized by the algorithm’s ordering.
Reversing the chain too early: predecessor links point toward the source, so collection naturally runs destination-to-source. Reverse once, after reaching the source. Returning only the predecessor: the output should include the source and destination as well as intermediate vertices.
Using Dijkstra with negative weights: its finalized-distance assumption can fail. Choose an algorithm suited to the weights. Also distinguish “no path” from a zero-length path: a distance of zero can be valid, while infinity or an explicit unreachable marker means no route was found.
Tips
- Store a vertex identifier in
prev[v], not an entire copied route. This keeps updates small and reconstruction straightforward. - Use a clear unreachable value, such as infinity, and a clear empty predecessor value, such as null. Avoid treating vertex ID zero as empty if zero is a valid vertex.
- If multiple routes have the same minimum distance, strict comparison (
<) keeps the first route found. Using<=can replace it with another equal route and may make results depend on traversal order. Either route is shortest, but use a consistent tie policy. - For many destination queries from one source, keep the predecessor table after the search and reconstruct each requested route when needed.
- If you need the actual edges as well as the vertices—for example, when parallel edges connect the same pair—store the chosen predecessor edge, not just the previous vertex.
Troubleshooting
The distance is correct but the route is missing: inspect the relaxation step and make sure prev[v] = u runs whenever dist[v] is improved. Confirm that the predecessor table is initialized and that it is not reset before reconstruction.
The route uses an edge in the wrong direction: check whether your graph is directed. Do not add reverse adjacency entries unless the graph is undirected or the reverse edge exists.
The chain ends before reaching the source: look for a missing predecessor update, an unreachable destination, or a mismatch between the source used for the search and the source used to stop reconstruction. A defensive implementation should detect a null link before reaching the source and report an inconsistent chain rather than returning a partial route.
The chain loops or becomes unexpectedly long: check that predecessor changes happen only on valid distance improvements and that the algorithm’s weight assumptions hold. Add a guard that limits the number of links followed to the number of vertices; exceeding it indicates a bug or corrupted predecessor data.
The reconstructed edge sum differs from the distance: check weight units, parallel edges, stale queue entries, and whether the stored predecessor identifies the same edge used in relaxation. For floating-point weights, compare using a small tolerance rather than requiring exact equality.
Frequently Asked Questions
Does predecessor tracking change the shortest distance?
No. It adds a record of the vertex that produced each improved distance. The search still uses the same distance comparisons.
Can I reconstruct every shortest path from one run?
Yes. A completed search from one source leaves a predecessor chain for each reachable vertex. Follow the chain from any such destination back to the source.
What if there are several equally short paths?
A single predecessor table returns one of them. The chosen route depends on tie handling and the order in which vertices or edges are processed.
Can a predecessor table represent all shortest paths?
Not by itself. To preserve every equally good route, store a collection of predecessors when candidates tie, then traverse that structure to enumerate paths. The number of such paths can be very large.
How do I return the path in the right order?
Collect destination, predecessor, and earlier predecessors until reaching the source, then reverse the collection once.
Does this work with A*?
Yes. A* can store a predecessor whenever it improves a vertex’s best-known path cost, then use the same backward reconstruction. Its heuristic and stopping conditions must be appropriate for the result you need.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Delete Picture Kik? How to Remove Photos
- What Happens to X Replies, DMs, and Followers After Deletion?
- Data Breaches That Shook the World
- Disable Google Assistant: Turn It Off on Android & Home
- Resin vs FDM Printers for Miniatures: Detail, Durability, Cost
- Are Networked Implants Safe? What If One Fails?