views:

41

answers:

2

I have a connected, directed, cyclic graph. The task is to discover every single node in the graph without falling into an infinite loop, as a regular tree traversal algorithm will do.

You can assume that I already know what node to start at so as to reach all points in the directed graph, and that for each node I have a function that will return the nodes it directs to. Is there a known algorithm for finding all nodes?

The main issue is really avoiding cycles, and I would love it if there was a way to do that without keeping track of every single node and comparing it with a list of nodes that has already been traversed.

If you need more details, the actual task is to get a list of every named function in JavaScript, including functions that are properties of other objects. So I tried something like the following, as I thought the JS objects' references to each other made a tree (but of course it doesn't):

function __findFunctions(obj){
  for (var f in obj){
    // for special case of edge with self
    if (obj === obj[f]){
      continue
    }
    if (typeof obj[f] === 'function' &&
        obj.hasOwnProperty(f) &&
          // exclude native functions, we only want user-defined ones
        !(/\[(native\scode|object\sfunction)\]/i).test(obj[f].toString()) &&
          // exclude functions with __ prefix
        !(/^\s*function\s*__/).test(obj[f].toString())
       ){
      document.write(f + "<br/>" + obj[f].toString() + "<hr/>");
    }
    //alert(typeof obj[f] + "\n" + obj + "\n" + obj[f] + "\n" + f)
    __findFunctions(obj[f]);
  }
}
__findFunctions(window);

The problem with this code is that it gets stuck in cycles.

A: 

You would need to maintain a list of already visited nodes if you want to avoid cycles.

E.g.

__findFunctions(obj, visited) as your signature
at start do an "in array" test for current obj and return if so.
at start add obj to the visited for subsequent traversals.
Graphain
+2  A: 

I would love it if there was a way to do that without keeping track of every single node and comparing it with a list of nodes that has already been traversed.

It may not be as bad as checking a list of already-traversed nodes. You could, instead, give each node a unique ID of some sort:

// psuedo
id=0;
for each node
    node.id = id++;

etc.

Then you can add each node's ID to a hash while you traverse:

var alreadyTraversed = {};

// Traversing a node:
alreadyTraversed[node.id] = true;

And later on, when you need to check whether or not its already been traversed:

if (node.id in alreadyTraversed) // It's already been traversed...

Or, for a really rudimentary solution, simply set some property on each object that you traverse:

node._traversed = true;

// Later:
if (someNode._traversed) // already traversed.
J-P
Your pseudo code won't work out unfortunately because the `for each node` is actually the graph traversal algorithm I seek. However, it does give me an idea, if JS allows it: use the node objects themselves as the IDs instead of an integer. I've done this sort of thing in Ruby, I'll give it a try in JS. Thanks!
ehsanul
@ehsanul: See my second proposed solution :)
J-P
Doh, great idea. Not only is it rudimentary, it's the right solution. Nowww I can sleep knowing there's a sensible solution for me to wake up to.
ehsanul
You wouldn't happen to know which JS objects besides strings can't have properties, would you?
ehsanul
`Null`, `Undefined`, `String`, `Boolean`, `Number` ... Although the last three can have properties, technically, but they won't retain them since they're not wrapped (try `new String()` instead...)
J-P