Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Dive into graph traversal: BFS for shortest unweighted paths, DFS for exhaustive discovery, plus weighted variants—Dijkstra, A*, bidirectional, and heuristic search. Understand frontier control and edge‑cost strategy for optimal exploration.
In contrast to searching within linear structures or hierarchical trees, graph search algorithms deal with traversing a general graph (which could be thought of as a network of connected nodes). Two fundamental graph search strategies are Breadth-First Search (BFS) and Depth-First Search (DFS). These algorithms systematically explore nodes and edges of a graph to find a target or to traverse all reachable nodes from a starting point. While they are often used for “traversal” (visiting all nodes) rather than direct key-based lookup, they are essential whenever the data forms a graph or network.
This article is all about searching inside Data Structures. For a more general article about Searching Algorithms, go to the main article: Search Algorithms: A Comprehensive Guide.
Depth-First Search explores a graph by going as deep as possible along one path before backtracking. It uses a stack implicitly or explicitly: it picks a starting node, explores one neighbor, then a neighbor of that neighbor, and so on, diving deeper until it can’t continue, at which point it backtracks and explores alternative branches.
How it works: There are two common implementations of DFS – recursive (which uses the call stack) or iterative (using an explicit stack data structure):
In essence, DFS follows one path until it dead-ends, then backtracks and tries another path. For example, if you are solving a maze by hand, a DFS approach is like always taking a turn and following a corridor as far as it goes, only backtracking when you hit a dead end.
Use in searching for a target: If you are looking for a particular node with some property, DFS can be used to find it. However, DFS does not guarantee the shortest path to the target, but it will find a path if one exists (assuming the graph is finite and connected). You may need to traverse a lot of nodes before luckily hitting the target, depending on the structure and where the target is.
Complexity: DFS runs in O(V + E) time, where V is the number of vertices (nodes) and E is the number of edges in the graph. This is because in the worst case DFS will traverse every edge and vertex once. The space complexity is O(V) in the worst case (because of the recursion stack or explicit stack usage). DFS can handle very large graphs as long as it has enough memory for recursion or stack.
Use cases: DFS is a general technique used in many graph algorithms and scenarios:
In summary, DFS is a fundamental tool for exploring graphs. It’s memory-efficient (only needs to store the stack of nodes on the current path) and straightforward to implement. However, if you need the shortest path in an unweighted graph or any notion of minimal steps, DFS might not be the best choice (you’d use BFS for that, described next). DFS, by virtue of going deep, can get “trapped” going down a long path that doesn’t lead to the goal before exploring shorter alternatives.
Breadth-First Search explores a graph in layers. It starts at a source node and first visits all nodes at distance 1 (all immediate neighbors), then all nodes at distance 2, and so on. BFS uses a queue to manage the frontier of exploration, ensuring that nodes are explored in increasing order of their distance from the start.
How it works:
u
.v
of u
that has not been visited, mark v
as visited and enqueue v
.By using a queue, BFS ensures that you first handle the starting node, then all its neighbors, then the neighbors’ neighbors, and so on. This results in a layered exploration:
If you visualize a graph as a ripple or wave emanating from the start node, BFS is like a wavefront that moves outward uniformly.
Key property – shortest paths: In an unweighted graph (where each edge has equal cost), BFS naturally finds the shortest path from the start node to any other node. The first time you encounter a node in BFS, you have reached it via the shortest possible route (fewest edges) from the start. This makes BFS the algorithm of choice for shortest-path problems in unweighted networks. For example, in a social network graph, BFS from a person will find all friends at distance 1 (direct friends), then distance 2 (friends of friends), etc. If you are looking for the degree of separation between two people, BFS will find it in the minimum number of hops.
Complexity: Like DFS, BFS runs in O(V + E) time, as it will end up exploring each vertex and each edge in the worst case. Space complexity is O(V) due to the queue and visited set (or boolean array). BFS can also handle large graphs, but if the graph is very wide (each node has many neighbors), the queue can grow quite large at peak (in the worst case, the last layer might have O(V) nodes in the queue).
Use cases: BFS is used whenever layer-by-layer exploration is needed or when shortest paths in terms of edge count are desired:
In summary, BFS and DFS are complementary strategies. BFS is great for shortest paths and layer-wise processing, while DFS is great for exhaustive search and depth-based tasks. Both ensure that every node is eventually explored (if the graph is connected or in each connected component separately), but the order of exploration differs, which gives them different practical applications. When using these algorithms, it’s important to handle marking of visited nodes properly, especially in graphs with cycles, to avoid infinite loops. Typically, a boolean visited structure or marking mechanism is used.
Searching through graphs is directly and intrinsically related to traversing and pathfinding through graphs. You can find more about these techniques and algorithms in the following articles:
For more search algorithms and techniques please go back to the main article: Search Algorithms: A Comprehensive Guide.