I have a representation of a tree using lists. For example:
(1 ((2 (3)) (3 (2)))) (2 ((1 (3)) (3 (1)))) (3 ((1 (2)) (2 (1)))))`
Now I need to traverse it level by level while maintaining the hierarchy tree. For instance:
- Traversing root node
(1)
- Traversing depth 1
(1 2) (1 3) (2 1) (3 1) (3 1) (3 2)
- Traversing depth 2
(1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1)
I can't figure out how to do it in Lisp. Any help (even a pseudo code) is appreciated. I have thought of several approaches but none of them seems legit.
Breadth-first search using an agenda
The classic way to do a breadth-first search is by maintaining an agenda: a list of things to look at next. Then you simply peel objects off the start of the agenda, and add their children to the end of the agenda. A very simple-minded approach to such an agenda is a list of nodes: to add to the end of the list you then use
append
.I can't understand your tree structure (please, when asking questions which need specification of a data structure or an algorithm give that specification: it is a waste of everyone's time to try to second-guess this) so I have made my own in terms of lists: a tree is a cons whose car is its value and whose cdr is a list of children. Here are functions to make and access such a tree structure, and a sample tree.
Now I never have to worry about the explicit structure of trees again.
Now here is a function which uses an agenda which will search this tree for a given node value:
For comparison here is a depth first search:
You can now compare these implementations by having a predicate which prints its argument but always fails, thus causing a traversal of the whole tree:
Appendix 1: a better agenda implementation
One problem with this naive agenda implementation is that we end up calling
append
all the time. A cleverer implementation allows items to be appended to the end efficiently. Here is such an implementation:Note that there is no way of copying one of these agendas provided.
Here is an explicitly iterative function which uses this 'clever' agenda:
Finally, any agenda-based search can easily be modified to be restartable: it simply needs to return the current agenda at the point it matched, and allow passing in of an agenda. Here is a variant of the above function which supports restarting searches:
Appendix 2: general search with an agenda
It is in fact possible to further generalise the agenda-based approach to searching trees. In particular:
The actual search implementation can be identical for these two cases, which is neat.
Below is some code which demonstrates this. This defines generic functions for tree access (with methods for cons-based trees) so nothing needs to care about that, and further defines a protocol for agendas with two concrete classes,
queue
andstack
which have appropriate methods. The search function is then completely agnostic about whether it does depth-first or breadth-first search, and is restartable in either case.This is a fairly substantial chunk of code: I'm leaving it here just in case it's useful to anyone.