views:

382

answers:

4

I need to search through a DAG graph, but I don't want to advance past a node before I have seen all of the other nodes that have directed links pointing to it.

Is there an existing algorithm to handle this particular situation, the depth first search and breath first search don't work for this order of traversal.

Ie:

A -> B
B -> C
C -> D
A -> C

I don't want to ever reach D before having seen both B and C.

A: 

You can't do that with an ordinary graph traversal algorithm because you're requiring that the algorithm magically have knowledge of graph structure that it can't have traversed without potentially violating its own requirements. You would have to use a two-pass approach that first builds backward trees telling you which nodes have connections in from which other nodes, then do a modified breadth-first search that uses the information from the first pass to delay traversal as appropriate. And I suspect that some graph structures might deadlock the second pass.

chaos
A: 

What about doing a topological sort first, then doing a depth first search over the sorted graph?

Would that work?

Dan
I think that would have to be a breadth-first search on the sorted graph.
swillden
A: 

Any DAG has at least one leaf node. Removing any leaf node node and all incoming arcs leaves another DAG. Recursively, this smaller DAG also has at least one leaf node. By recursively removing all nodes in this fashion, eventually the root node becomes a leaf node.

If you now reverse the order in which you removed the nodes, you have a traversal order which has the desired properties. By visiting leaf nodes last, you guarantee to have seen all parent nodes first.

MSalters
Thanks, this is otherwise known as a topological sort, and is implemented just like this in Boost :) Now how would I go from this ordered list of nodes to searching over only the nodes that are downstream of any particular node (still using this order), preferably without writing my own traversal algorithm?
Dan
You mean, when that particular node is _not_ the root node? Seems simple: topologically sort the entire DAG, and throw out all nodes that are not reachable from your particular node. The remaining nodes are a traversal order for the subgraph rooted in your particular node.
MSalters
A: 

So my latest thoughts are to do a topological sort over the entire graph whenever an edge is added or removed and store the order of immediate child nodes to be traversed for each node (which may be a bit of a tricky algorithm to write).

Then I do a modified breadth first search (as suggested by chaos), and in the following bfs pseudo-code, modify the line:

for each vertex v in Adj[u]

to be:

for each vertex v in OrderedAdj[u]

pseudocode:

BFS(G, s)
  for each vertex u in V[G]
    color[u] := WHITE 
    d[u] := infinity 
    p[u] := u 
  end for
  color[s] := GRAY 
  d[s] := 0 
  ENQUEUE(Q, s)
  while (Q != Ø) 
    u := DEQUEUE(Q)
    for each vertex v in Adj[u]
      if (color[v] = WHITE)
        color[v] := GRAY 
        d[v] := d[u] + 1  
        p[v] := u  
        ENQUEUE(Q, v)
      else
        if (color[v] = GRAY) 
          ...
        else 
          ...
    end for
    color[u] := BLACK
  end while
  return (d, p)

I believe this is the most optimal way of achieving this, but does involve me writing my own bfs traversal algorithm, plus storing the order of nodes on each node (an overhead in memory I was hoping to avoid), and writing my own dfs visitor for finding the order and storing this on the nodes in the caching stage.

I am surprised that there isn't an existing way of doing this though, as it seems to me a fairly common way of navigating a dag graph...

Dan