Search code examples
prologdcg

Prolog in-order traversal


Example of the node looks like:

node(3, nil, 14).
node(14, nil, 15).
node(15, nil, 92).

I have seen similar questions asked here however mine is different as my nodes have 3 instead of 2 values in the parameter.

Example of how it should run:

?- inOrder(3, X).
X = [3, 14, 15, 35, 65, 89, 92] .

My current code is:

 % the in-order traversal of a leaf is the leaf
 inOrder(X, [X]) :-
    node(X, nil, nil).

 % if the node only has a left child, we traverse that
 inOrder(x, [X|T]) :-
    node(X, L, [X|T]),
    inOrder(L, T).
 % if the node only has a right child we traverse that
 inOrder(x, [X|T]) :-
    node(X, nil, R),
    inOrder(R, T).
 % if the node has both, we traverse them both.
inOrder(x, [X|T]) :-
    node(L, X, R),
    L \= nil, R \= nil,
    inOrder(L, T1),
    inOrder(R, T2),
    append(T1, T, T2).

It returns false instead of an actual value.


Solution

  • There are several twists in your representation. In general, treelike structures are not flattened out in the database, here with node/3, but rather maintained in a single term.

    Also, it seems to be a good idea to insist that each node has its own fact. In your example 92 needs a fact!

    So given all these precautions one can write, using DCGs:

    node(3, nil, 14).
    node(14, nil, 15).
    node(15, nil, 92).
    node(92, nil, nil).    % added!
    
    inorder(I, Xs) :-
       phrase(inorder(I), Xs).
    
    inorder(nil) -->
       [].
    inorder(I) -->
       {dif(I, nil)},
       {node(I, L, R)},
       inorder(L),
       [I],
       inorder(R).
    
    ?- inorder(3,L).
       L = [3,14,15,92]
    ;  false.
    

    The check your database for orphaned nodes:

    orphan(Nr) :-
       node(_, L, R),
       ( Nr = L ; Nr = R ),
       dif(Nr, nil),
       \+ node(Nr, _, _).
    

    So orphan(N) should fail on your database.

    To get rid of the leftover choicepoint ; false. add the following rule in front of inorder//1:

    inorder(Nil) --> {Nil == nil}, !.