Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithms for Directed Cyclic Graph Traversal (JavaScript)

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.

like image 584
ehsanul Avatar asked Aug 22 '26 22:08

ehsanul


1 Answers

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.
like image 66
James Avatar answered Aug 25 '26 13:08

James