For the sake of example, let us assume the following representation for a tree:
- The atom
nil
represents the empty tree.
- The structure
tree/3
represents a non-empty tree tree( Left , Right , Payload )
where Left
and Right
represent (respectively and recursively) the left and right subtrees, and Payload
is the payload for the node: in your case, a list.
Many/Most recursive problems have 1 or 2 "special cases" and the more general case. This is no different:
The special case is that of the empty tree: flattening it produces the empty list.
The general case is that of a non-empty tree: flatting it consists of the following steps:
The Prolog code to accomplish this is pretty much identical to the English description above:
flatten_tree( nil , [] ) . % flattening the empty tree yields an empty list, n'est-ce-pas?
flatten_tree( tree(Left,Right,Payload) , Result ) :- % flattening a non-empty tree consists of
flatten_tree( Left , Prefix ) , % - flattening the left subtree,
flatten_tree( Right , Suffix ) , % - flattening the right subtree,
concatenate( Prefix , Payload , Suffix , Result ) % - concatenating the three parts
. % - easy!
concat( Xs, Ys , Zs , Rs ) :-
append(Xs,Ys,T1) ,
append(T1,Zs,Rs)
.
One might note that another approach might be to use findall/3
and append/2
(if you're using SWI prolog).
First you need a predicate to visit the tree via backtracking:
visit( tree(L,_,_) , P ) :- visit( L , P ) . % visit the left subtree
visit( tree(_,_,P) , P ) . % visit the current node
visit( tree(_,R,_) , P ) :- visit( R , P ) . % visit the right subtree
Feel free to rearrange the order of the clauses to get the ordering you'd like. Once you have that, flattening the tree is trivial:
flatten_tree( Tree , List ) :-
findall( X, visit(Tree,X) , Xs ) ,
append(Xs,List)
.