Depth-first search (C Plus Plus)

Depth-first search is simple to implement in a procedural language like C++ because it always expands the node most recently seen, making it ideal to implement with a stack (such as the procedural call stack).

Contents

Since we'll need to traverse through all the children of each node we visit, we choose an adjacency-list representation for the graph, templating over the node data type and creating a std::list of successor vertices:

As our terminating condition, we check if the start node is a goal vertex by applying the goal predicate to it. If so, we return true immediately and the result is propagated back up to the initial caller:

Finally, if the graph we're processing might contain directed cycles (it's not a directed acyclic graph), we need to ensure we don't get stuck in an infinite recursion following a cycle. To do this, we simply search the list of visited nodes in result for the start node and return false immediately if we've followed a cycle:

This small test driver demonstrates use of the search function on the Petersen graph, a small graph with 10 vertices and diameter 2. We'll see that the path found by depth-first search can be much longer than the minimum 2 vertices.

First we have the code that generates the graph as a simple vector of vertices, labelling the vertices with sequential integers:

Now we add the edges. We simply create a table of the edges and iterate over it. Note that since our data structure describes directed graphs, we need an edge in each direction for each edge of the graph:

On large graphs, the cycle-checking step can become expensive, because the result list may become very long. One solution is to also maintain a set data structure holding the nodes visited so far, such as a std::set. Another more common solution is to give each node a visited flag, which has the advantage that no node is ever expanded twice, but has the disadvantage that we need to make an initial pass to clear the flag on every node of the graph. Visited flags also make it difficult to make the algorithm threadsafe.

Another issue on large graphs is that depth-first search can easily form a very long call chain following a useless path. It's useful to include a threshold on how deep we want to search. By searching with incrementally larger thresholds, we get iterative deepening depth-first search, which finds much shorter paths in general than ordinary depth-first search.