30

How can I traverse an n-ary tree without using recursion?

Recursive way:

traverse(Node node)
{
    if(node == null)
        return;

    for(Node child : node.getChilds()) {
        traverse(child);
    }
}
BiGYaN
  • 6,974
  • 5
  • 30
  • 43
ako
  • 2,511
  • 3
  • 18
  • 11
  • 14
    Any recursive algorithm can be reduced to a loop + stack, so that's not much of a restriction. Have at it with any of the algorithms that can be found on [Google](http://www.google.com.au/search?q=n-ary+tree+traversal). – Matthew Scharley May 13 '11 at 06:10
  • 1
    I'm in a good mood, so I've translated your algorithm for you. In general, it's not a terribly difficult thing to do though, and a quick google would have turned up [many results](http://en.wikipedia.org/wiki/Tree_traversal#Queue-based_level_order_traversal) for this. Tree traversal is a very well-defined problem by this point in history. – Matthew Scharley May 13 '11 at 06:26
  • Just interesting @ako. Why do you want to do it without recursion? Is there any reason or this is just question to earn reputation? – Mihran Hovsepyan May 13 '11 at 07:56
  • 3
    @mihran why would a user join stack overflow to gain reputation at a site they haven't used previously? – Nicolas78 May 13 '11 at 22:31

3 Answers3

37

What you are doing is essentially a DFS of the tree. You can eliminate recursion by using a stack:

traverse(Node node) {
    if (node==NULL)
        return;

    stack<Node> stk;
    stk.push(node);

    while (!stk.empty()) {
        Node top = stk.pop();
        for (Node child in top.getChildren()) {
            stk.push(child);
        }
        process(top);
    }
}

If you want a BFS use a queue:

traverse(Node node) {
    if (node==NULL)
        return;

    queue<Node> que;
    que.addRear(node);

    while (!que.empty()) {
        Node front = que.deleteFront();
        for (Node child in front.getChildren()) {
            que.addRear(child);
        }
        process(front);
    }
}

In case you want some other way to traverse, you'll have to follow the same approach albeit with a different data structure to store the node. Maybe a priority queue (if you want to evaluate a function at each node and then process nodes based on that value).

BiGYaN
  • 6,974
  • 5
  • 30
  • 43
19

You can do this without recursion and without a stack. But you need to add two extra pointers to the node:

  1. The parent node. So you can come back to the parent if you are finished.
  2. The current child node so you know which one to take next.

    • For each node, you handle all the kids.
    • If a kid is handled, you check if there is a next kid and handle that (updating the current).
    • If all kids are handled, go back to the parent.
    • If the node is NULL, quit.

With pseudocode this looks like:

traverse(Node node) {
  while (node) {
    if (node->current <= MAX_CHILD) {
      Node prev = node;
      if (node->child[node->current]) {
        node = node->child[node->current];
      }
      prev->current++;
    } else {
      // Do your thing with the node.
      node->current = 0; // Reset counter for next traversal.
      node = node->parent;
    }
  }
}
Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
  • 1
    Ok, now I get it. However, this solution imposes an awful lot of constraints on the data-structure. And that's not even talking about multi-threading. – Björn Pollex May 13 '11 at 06:42
  • 1
    @Space_C0wb0y, true, this is just another way to show that the recursive way is the clearest. – Toon Krijthe May 14 '11 at 07:24
10

No language given, so in pseudo-pseudocode:

traverse(Node node)
{
  List<Node> nodes = [node];

  while (nodes.notEmpty) {
    Node n = nodes.shift();

    for (Node child in n.getChildren()) {
      nodes.add(child);
    }

    // do stuff with n, maybe
  }
}

Note that this is a breadth-first traversal as opposed to the depth-first traversal given in the question. You should be able to do a depth-first traversal by poping the last item off the nodes list instead of shifting the first one.

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
  • if you use pop instead of shift, it wouldn't be DFS as it would still start with the root node. DFS starts with the deepest (left) leaf. – Marco M. Sep 26 '12 at 19:42
  • @MarcoM. The OP's solution will search the root first too since it uses tail recursion. It's close enough for most practical applications I think. – Matthew Scharley Sep 27 '12 at 00:12