0

I have a recursive algorithm for traversing nodes in a document tree in tree order

How would this be made iterative? My attempt at making it iterative completely failed

function recursivelyWalk(nodes, cb) {
    for (var i = 0, len = nodes.length; i < len; i++) {
        var node = nodes[i],
            ret = cb(node)

        if (ret) {
            return ret
        }

        if (node.childNodes.length) {
            var ret = recursivelyWalk(node.childNodes, cb)
            if (ret) {
                return ret
            }
        }
    }
}
5
  • For iterative way you can use Q. Commented Mar 3, 2012 at 19:32
  • @SaeedAmiri might mean queue. What is the reason you're trying to avoid recursion here? Commented Mar 3, 2012 at 19:35
  • Q is queue I thought it's obvious. Commented Mar 3, 2012 at 19:52
  • 6
    @SaeedAmiri, writing out "queue" is even more obvious. Commented Mar 3, 2012 at 19:57
  • @Jordan one avoids recursion due to lack of tail call optimisation Commented Mar 3, 2012 at 19:59

2 Answers 2

2

What about concatenating the child nodes if there are any, and using a while(nodes.length) loop? Basically, keep adding new nodes to the stack, and keep running the loop (testing one node each time) until the stack is empty: http://jsfiddle.net/gEm77/1/.

var z = 0; // my precaution for a while(true) loop

function iterativelyWalk(nodes, cb) {
    nodes = [].slice.call(nodes);

    while(++z < 100 && nodes.length) {
        var node = nodes.shift(),
            ret = cb(node);

        if (ret) {
            return ret;
        }

        if (node.childNodes.length) {
            nodes = [].slice.call(node.childNodes).concat(nodes);
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

That would work if it was changed to enforce tree order. nodes = [].slice.call(node.childNodes).concat(nodes) should preserve tree order
@Raynos: Good call; edited. The new nodes should indeed be pushed to the beginning of the array due to .shift().
2

This article (linked from Wikipedia's article on tree traversal) gives an algorithm in JavaScript for iterative preorder traversal of a DOM tree. To quote:

function preorderTraversal(root) {
  var n = root;
  while(n) {
  // If node have already been visited
    if (n.v) {
      // Remove mark for visited nodes
      n.v = false;
      // Once we reach the root element again traversal
      // is done and we can break
      if (n == root)
        break;
      if (n.nextSibling)
        n = n.nextSibling;
      else
        n = n.parentNode;
    }
    // else this is the first visit to the node
    else {
      //
      // Do something with node here...
      //
      // If node has childnodes then we mark this node as
      // visited as we are sure to be back later
      if (n.firstChild) {
        n.v = true;
        n = n.firstChild;
      }
      else if (n.nextSibling)
        n = n.nextSibling;
      else
        n = n.parentNode;
    }
  }
}

Note the line "// Do something with node here...", which is where you can call your callback function.

Check out the full article for more information.

1 Comment

That's an ugly implementation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.