What is the best way to visit all the nodes of a linked tree (all nodes have references to parent and all children, root nodes have null as parent), so that no node is visited before any of its ancestors? Brownie points for non-recursive.
10 Answers
Pseudo code:
NodesToVisit = some stack or some list
NodesToVisit.Push(RootNode)
While NodesToVisit.Length > 0
{
CurNode = NodesToVisit.Pop()
For each Child C in CurNode
NodesToVisit.Push(C)
Visit(CurNode) (i.e. do whatever needs to be done)
}
Edit: Recursive or not?
To be technically correct, and as pointed out by AndreyT and others in this post, this approach is a form of a recursive algorithm, whereby an explicitly managed stack is used in lieu of the CPU stack and where the recursion takes place at the level of the While loop. This said, it differs from a recursive implementation per se in a couple of subtle yet significant ways:
- Only the "variables" are pushed onto the stack; there is no "stack frame" and associated return address on the stack, the only "return address" is implicit to the while loop, and there is but one instance of it.
- The "stack" could be used as a list whereby the next "frame" could be taken anywhere in the list, without braking the logic in any way.
-
OK. This wasn't an academic question. It was a practical question. This answers it in a satisfactory way without making me think or do any further reading. Thanks. (It will probably make me think later when I get the time, but that's fine... Useful, even...) Job's done. Thanks again :) – George Oct 26 '09 at 23:45
You're looking for a preorder traversal. I think you can do it non-recursively with a queue:. In pseudocode:
Create an empty queue, then push the root node.
while nonempty(q)
node = pop(q)
visit(node)
foreach child(node)
push(q,child)

- 43,505
- 7
- 82
- 96
-
That would be a *non-recirsive implemenation* of a *recursive algorithm*. Replacing implied stack with explicit stack doesn't turn a recursive algorithm into a non-recursive one. In fact, it doesn't change the algorithm at all. What you have above is obviously recursive (as far as algorithm is concerned). – AnT stands with Russia Oct 23 '09 at 23:13
-
5Typically when people say they don't want recursion, they're referring to function-level recursion. This satisfies that condition. – JSBձոգչ Oct 23 '09 at 23:14
-
Well, sometimes yes. However, the problem we are considering here is specifically crafted to allow truly non-recursive solution (i.e. non-recursive algorithm). The dead giveaway is the presence of parent pointers. Your "non-recursive" solution doesn't use parent pointers. Don't you wonder why they are even there? They are there specifically to allow a true non-recursive solution, the one with O(1) memory requirement. – AnT stands with Russia Oct 23 '09 at 23:22
-
But most of the time - no. Typically when people say they don't want recursion, they mean that they don't want the memory requrements of recursion, i.e. they don't want to have a non-constant-sized data structure for storing "subproblems", be it FIFO, LIFO or whatever else. – AnT stands with Russia Oct 23 '09 at 23:30
-
2@AndreT: I don't think I've ever heard "non-recursive" used to mean "constant space requirement" as you seem to believe. So I have to disagree that your usage is "typical". – Jim Lewis Oct 23 '09 at 23:36
-
@Jim Lewis: Firstly, it is not just "constant space requirement" in general (I never said that). It is constant number of "scheduled" subtasks (and, therefore, constant space for storing these subtasks). Secondly, that's too bad that you never heard about it. Becuase this is actually a defining property of non-recursive *algorithm*. The lack of understanding of what the term "recursive algorithm" means, and the lack of understanding of the difference between "algorithm" and "implementation" is rather appaling these days. – AnT stands with Russia Oct 23 '09 at 23:45
-
When people come up with a non-recursive *implementation* by implementing recursive *algorithm* with a hand-made stack (as opposed to using a functional stack), and then call it *non-recursive algorithm*... That's just... well... ridiculous, for the lack of better word. – AnT stands with Russia Oct 23 '09 at 23:47
-
@AndreyT: And it might be an easy way to walk around function-stack limits in programming languages like Python... – mozzbozz Oct 28 '14 at 10:58
If you have links to all children and to the parent as well, then non-recursive algorithm is rather trivial. Just forget that you have a tree. Think of it is a labirynth where each parent-child link is an ordinary bi-directional corridor from one junction to the other. All you need to do to walk the entire labyrinth is to turn into the next corridor on the left at each junction. (Alternatively, think of it as walking the labyrinth with your left hand always touching the wall on the left side). If you start from the root junction (and move in any direction), you'll walk the entire tree always visiting parents before children. Each "corridor" in this case will be travelled twice (in one direction and in the other), and each "junction" (node) will be visited as many times as many "corridors" join it.

- 312,472
- 42
- 525
- 765
Use a set of nodes. Put the root in the set to start. Then in a loop, pull a node out of the set, visit it, then put its children in the set. When the set is empty, you are done.

- 22,985
- 2
- 35
- 54
-
You want the data structure to be FIFO, not just any old container, to guarantee the preorder condition. – Jim Lewis Oct 23 '09 at 23:08
-
In pseudocode:
currentList = list( root )
nextList = list()
while currentList.count > 0:
foreach node in currentList:
nextList.add(node.children)
currentList = nextList

- 40,684
- 18
- 101
- 169
If you start at the root node, and only visit the parents/children of nodes you have already visited, there is no way to traverse the tree such that you visit a node before visiting its ancestors.
Any sort of traversal, depth first (recursive/stack based), breadth first (queue based), depth-limited, or just pulling them out of an unordered set, will work.
The "best" method depends on the tree. Breadth first would work well for a very tall tree with few branches. Depth first would work well for trees with many branches.
Since the nodes actually have pointers to their parents, there is also a constant-memory algorithm, but it is much slower.

- 48,337
- 13
- 89
- 105
-
Teh op said "*no* node is visited before its ancestors". So it's the other way around. – AnT stands with Russia Oct 23 '09 at 23:28
-
Maybe not. I thought that in your first sentence you claimed that the problem cannot be solved, since the visitation order requrement (which, I assumed, you misunderstood) is impossible to satisfy. – AnT stands with Russia Oct 23 '09 at 23:53
-
I was making the point that ANY traversal (starting from the root node) would meet the requirement. – Artelius Oct 24 '09 at 00:06
I would disagree with breadth first search as space complexity is often the bane of that specific search algorithm. Possibly using the iterative deepening algorithm is a better alternative for this type of use, and it covers the same type of traversal as breadth first search. There are minor differences in dealing with the fringe from breadth-first search, it shouldn't be too hard to (pseudo) code out though.

- 1,018
- 1
- 8
- 15
-
+1 because of your consideration space complexity - but why not just use a depth-first search? – Artelius Nov 02 '09 at 05:10
-
Many trees in practice tend to be deeper than they are 'wider', esp. in AI decision-making processes. The question does not state whether the tree is finite, but you could run into a loop. One of the reasons iterative deepening is liked is that it is complete (will find a solution). – mduvall Nov 02 '09 at 09:11
Here's a truly non-recursive approach: no stack, constant space. This Python code assumes that each node contains a list of children, and that the node objects do not define equality, so that the 'index' function is comparing identities:
def walkTree(root, visit_func):
cur = root
nextChildIndex = 0
while True:
visit_func(cur)
while nextChildIndex >= len(cur.children) and cur is not root:
nextChildIndex = cur.parent.children.index(cur) + 1
cur = cur.parent
if nextChildIndex >= len(cur.children):
break
cur = cur.children[nextChildIndex]
nextChildIndex = 0
I'm sure it could be polished up a bit, made more concise and easier to read, but that's the gist.

- 4,795
- 2
- 23
- 28
Build up a list of nodes at the root (level 0), iterate over each node in turn and look for direct children (whose parent node is the node we are currently looking from) (level 1), when finished with level 0 move on to iterating level 1, and so on until you have no remaining unvisited nodes.

- 635
- 6
- 19