Shortest path DFS, BFS or both?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
The right shortest-path algorithm depends on graph structure and edge cost model, not personal preference for DFS or BFS syntax. In unweighted graphs, BFS is the correct baseline for shortest path by edge count. DFS is useful for traversal tasks, but plain DFS does not guarantee shortest path.
Unweighted Graphs: Use BFS
BFS explores nodes layer by layer from the source. The first time a node is reached, BFS has found a path with minimum number of edges from the source.
This is the most direct answer when edges are all equal cost.
Why DFS Alone Is Not a Shortest-Path Method
DFS goes deep before exploring siblings. The first found path may be much longer than the shortest one. You can force DFS to enumerate many paths and pick the best, but that is usually expensive and not the standard approach.
DFS remains very useful for:
- Reachability checks.
- Cycle detection.
- Topological ordering in DAG workflows.
- Backtracking and constraint search.
Use DFS for these goals, not as the default shortest path routine.
Weighted Graphs: Use Dijkstra
If edges have non-negative weights, shortest path means minimum total weight, not fewest edges. Dijkstra is the usual baseline.
If negative edges exist, use Bellman-Ford or a different model-specific method.
Should You Use Both DFS and BFS
Sometimes yes, but usually for separate purposes in the same system:
- BFS for shortest path in unweighted navigation.
- DFS for cycle analysis or dependency inspection.
Another related optimization is bidirectional BFS, which runs BFS from source and target in large unweighted graphs. That is still BFS logic, just from both ends.
Complexity and Scaling Notes
With adjacency lists:
- BFS time is
O(V + E). - DFS time is
O(V + E). - Dijkstra with binary heap is around
O((V + E) log V).
Complexity alone is not enough. Memory behavior matters:
- BFS can use large memory on wide frontier layers.
- DFS stack is smaller in wide graphs but loses shortest guarantee.
Pick algorithm based on correctness first, then optimize implementation details.
Path Reconstruction Best Practice
Many beginners only compute distance and forget to store predecessors. Real systems often need the actual route for display, simulation, or follow-up actions. Storing parent during traversal is the simplest robust pattern.
Also define behavior for unreachable nodes explicitly, for example returning None or raising a domain-specific exception.
Common Pitfalls
- Using DFS and assuming first-found path is shortest.
- Applying BFS to weighted graphs where edge costs differ.
- Forgetting predecessor tracking when the caller needs actual path.
- Ignoring unreachable-case behavior in API contract.
- Optimizing for speed before proving algorithmic correctness.
Summary
- Use BFS for shortest path in unweighted graphs.
- Use Dijkstra for weighted graphs with non-negative edges.
- Do not use plain DFS as a shortest-path algorithm.
- Use DFS for traversal tasks such as cycles and reachability.
- Define clear return behavior for unreachable targets and path reconstruction.
Related reading
- Shortest path fewest nodes for unweighted graph
- Shortest path in absence of the given edge
- Shortest path in graph where cost depends on the history of traversing
- Shortest path on a graph where distances change dynamically? maximum energy path
- Shortest path to visit all nodes
- Shortest path with even number of edges
- Shortest Path to accomplish given scenario
- Shortest path to transform one word into another

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.