问题
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.
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/3201381/algorithms-for-directed-cyclic-graph-traversal-javascript