In Order Tree Traversal en Prolog

I'm new to Prolog and I'm trying write an in-order tree traversal where given a list of facts such as:

leftSubtree(9, 7).
leftSubtree(7, 1).
leftSubtree(1, -2).
leftSubtree(11, 9).
leftSubtree(16, 13).
leftSubtree(3, 2).
rightSubtree(9, 11).
rightSubtree(7, 6).
rightSubtree(1, 3).
rightSubtree(11, 16).
rightSubtree(16, 19).

I can use inOrder(9,X). to print out a the tree in order. I tried using the following code which works but was hoping for something simpler. Any tips or assistance would be appreciated.

inOrder(Root, X):-
   \+ leftSubtree(Root,Left),
   \+ rightSubtree(Root,Left) ->
   X = [Root];
   inOrder(Left, LeftNode),
   inOrder(Right, RightNode),
   inOrder(Left, LeftNode),
   inOrder(Right, RightNode),

preguntado el 01 de febrero de 12 a las 03:02

Why did you delete 90% of your question? The original was clear on the problem and the tree structure, and showed you'd put some effort into solving it yourself. Now it's not even a question... -

3 Respuestas

Your code can be simplified, avoiding negative tests, and using some of the reflexivity of Prolog.

inOrder(Root, [Left, Root, Right]) :-
  inOrder(leftSubtree, Root, Left),
  inOrder(rightSubtree, Root, Right).

inOrder(BranchToExplore, Root, Subtree) :-
   call(BranchToExplore, Root, Branch)
   ->  inOrder(Branch, Subtree)
   ;   Subtree = [].

This recover the estructura of the tree, as a nested ternary list, then a single call of flatten/2 suffices to make it, well, plano, as in your original requirement.

?- inOrder(8, Tree), flatten(Tree, L).
Tree = [[[[[], -2, []], 1, [[[], 2, []], 3, []]], 5, [[], 6, []]], 8, [[[], 9, [[], 10|...]], 11, [[[], 13|...], 16, [...|...]]]],
L = [-2, 1, 2, 3, 5, 6, 8, 9, 10|...].

If your Prolog doesn't have call/N, you can use univ para construir un invocable término:

inOrder(BranchToExplore, Root, Subtree) :-
  ( Callable =.. [BranchToExplore, Root, Branch], call(Callable) )
  ->  inOrder(Branch, Subtree)
  ;   Subtree = [].

If we swap Left and Root we have the more useful preOrder representation: preOrder(Root, [Root, Left, Right]) :- ....

Having the structure of the tree in preOrder can be useful for further process: one 'ready to go' and useful implementation in SWI-Prolog it's XML, where trees are represented as element(Tag, Attributes, Subtrees), and can be handled by library(xpath). Could be an useful exercise change both inOrder/2 and inOrder/3 to recover XML.

Respondido 01 Feb 12, 12:02

Prueba esto:

inOrder(N,X) :- traverseLeft(N,L), traverseRight(N,R), append(L,[N|R],X).
traverseLeft(N,L) :- leftSubtree(N,M) -> inOrder(M,L); L=[].
traverseRight(N,R) :- rightSubtree(N,M) -> inOrder(M,R); R=[].

There's still a bit of room for improvement. append/3 is quite expensive, but you can avoid this by using accumulators.

The idea of an accumulator is that instead of writing a predicate inOrder(N,X), meaning "the in-order traversal of the tree rooted at N is X", you write inOrder(N,A,X), meaning "the in-order traversal of the tree rooted at N, appended to A, is X". Then you just kick it off by calling inOrder(Root,[],X).

The point of this is that you can get your recursive calls to build their solutions on top of your existing list, and avoid a linear-time list concatenation at every step.

inOrder(N,X) :- inOrder_aux(N,[],X).
inOrder_aux(N,A,X) :- traverseLeft(N,[N|R],X), traverseRight(N,A,R).
traverseLeft(N,A,L) :- leftSubtree(N,M) -> inOrder_aux(M,A,L); L=A.
traverseRight(N,A,R) :- rightSubtree(N,M) -> inOrder_aux(M,A,R); R=A.

So it's pretty much the same as the original solution, except that the base cases return the accumulator instead of the empty list, and you pass the result of the right traversal in as the accumulator of the left (before the right traversal has happened, as strange as that might seem).

Respondido 01 Feb 12, 14:02

Trees are better represented in Prolog by logical terms. A thorough discussion, including an answer to your problem can be found here (see solutions)

Respondido 07 Feb 12, 19:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.