views:

332

answers:

3

Hi, I'm curious if there is a specific graph algorithm that traverses an unweighted acyclic directed graph by choosing a start node and then proceeding via DFS. If a node is encountered that has unsearched predecessors then it should back track the incoming paths until all paths to start have been explored.

I found a wikipedia category for graph algorithms but there is a small sea of algorithms here and I'm not familiar with most of them.

EDIT: example: given the graph {AB, EB, BC, BD}, traverse as: {A,B,E,B,C,D} or unique order as {A,B,E,C,D}. Note this algorithm unlike BFS or DFS does not need to begin again at a new start node if all paths of the first start node are exhausted.

+2  A: 

What you are looking for is the topological sort. As far as I'm aware there's no easy way to traverse a graph in its topologically sorted order without any precomputation.

The standard way to get the topsort is to do a standard DFS, and then store the visited nodes in order of their visiting times. Finally, reverse those nodes and voila, you have them in the order you desire.

Pseudocode:

list topsort

procedure dfs(vertex u)
  mark u as visited
  for each edge (u, v)
    if v not visited
      dfs(v)
  add u to the back of topsort

The list topsort will then contain the vertices in the reverse order that you want. Just reverse the elements of topsort to correct that.

Peter Alexander
I think this might be right. I'll look close soon and get back to you.
harschware
Knuth also published at least one interesting topological sort, useful if your edges are stored in an array. First, you count how many predecessors each node has. Those with zero are queued. As you extract items from that queue, you decrement predecessor counts for successors, adding items to the queue as the counts hit zero. The interesting bit is how efficiently this is handled, but Google is annoying me - I can't find a good link ATM for the details.
Steve314
+2  A: 

In DFS, you usually choose the vertex to be visited after u based on the edges starting at u. You want to choose based first on the edges ending at u. To do this, you could have a transpose graph info, and try to get the vertex from there first.

It would be something like this:

procedure dfs(vertex u)
  mark u as visited
  for each edge (v, u) //found in transpose graph
    if v not visited
      dfs(v)
  for each edge (u, w)
    if v not visited
      dfs(w)
Samuel Carrijo
+2  A: 

If you're looking for topological sort, you can also do this, given an adjacency list (or a list of edges (u,v) which you can preprocess in O(E) time):

list top_sort( graph in adjacency list )
     parent = new list
     queue = new queue
     for each u in nodes
         parent(u) = number of parents
         if ( parent(u) is 0 ) // nothing points to node i
             queue.enqueue( u )

     while ( queue is not empty )
         u = queue.pop
         add u to visited
         for each edge ( u, v )
             decrement parent(v) // children all have one less parent
             if ( parent(v) is 0 )
                 queue.enqueue( v )

Given an adjacency list (or a list of edges (u,v)), this is O( V + E ), since each edge is touched twice - once to increment, once to decrement, in O(1) time each. With a normal queue, each vertice will also be processed by the queue at most twice - which can be done also in O(1) with a standard queue.

Note that this differs from the DFS (at least a straight-up implementation) in that it handles forests.

Another interesting note is that if you substitute queue with a priority_queue imposing some sort of structure/ordering, you can actually return the results sorted in some order.

For example, for a canonical class dependency graph (you can only take class X if you took class Y):

100:
101: 100
200: 100 101
201: 
202: 201

you would probably get, as a result:

100, 201, 101, 202, 200

but if you change it so that you always want to take lower numbered classes first, you can easily change it to return:

100, 101, 200, 201, 202
Larry