'How to count the leaves of a tree in prolog?

I am trying to sum the leaves of a tree and cannot seem to do it correctly any help would be greatly appreciated. I have tried several different methods and none seem to work right.

nleaves(nil, 0).
nleaves(node(_,Left,Right), N) :- 
    nleaves(Left, N1),
    nleaves(Right, N2),
    N is N1 + N2.

when I ask the query ?- nleaves(3, node(1, node(2, node(3, nil, nil), node(4, nil, nil)), node(5,nil,nil)), N)., it comes back with N = 0. Now, if I replace 0 with 1 in the base case and ask the same query, it returns N = 6. Then if I completely manipulate the predicate which is completely wrong and not acceptable

nleaves(nil, 0).
nleaves(node(_, Left, Right), N) :- 
    nleaves(Left, LN), 
    nleaves(Right, RN),
    N is 3 - LN + RN.

It will then spit out N = 3.

What can I do to this to make it say N = 3 the right way? I am at a loss for counting the leaves. I seem to be able to count the height correctly with a max predicate helper.

height(nil, 0). % base case empty tree height is 0.
height(node(_,Left,Right), N) :- 
    height(Left, LN), 
    height(Right, RN),
    N is max(LN, RN) + 1.

but I cannot figure out how to count the leaves.



Solution 1:[1]

The base predicate should be one for a leaf, and 0 for a nil, so:

nleaves(nil, 0).
nleaves(node(_, nil, nil), 1).
nleaves(node(_, Left, Right), N) :-
    (dif(Left, nil); dif(Right, nil)),
    nleaves(Left, L),
    nleaves(Right, R),
    N is L + R.

Here the second clause thus counts a leaf node(_, nil, nil) as one, and a node where at least one of the two items is not nil as the sum of the leaves of the two nodes.

Solution 2:[2]

So a leaf is a node pointing to 2 nils, right?

nleaves(nil,0).
nleaves(node(_,nil,nil),1).
nleaves(node(_,Left,Right),N):- 
    dif((Left,Right), (nil,nil)),
    nleaves(Left,N1),
    nleaves(Right,N2),
    N is N1+N2.

Solution 3:[3]

This is a strange definition of a tree; the more normal definition has a type that looks like this:

leaf(Value)
node(Left, Right)

Then you can traverse it like this (I'm using DCG notation -- if you don't understand what's going on, do the query listing(preorder) to see the code expansion):

preorder(leaf(Value)) --> [Value].
preorder(node(Left, Right)) -->
    preorder(Left),
    preorder(Right).

%           *
%         /  \
%       1
%           /  \
%               4
%         / \
%        2   3

test(Values) :-
    phrase(preorder(
                    node(leaf(1),
                         node(node(leaf(2), leaf(3)),
                              leaf(4)))),
           Values).
?- test(V).
V = [1, 2, 3, 4].

If you want to know how many leaves, just use the length/2 predicate on Values. Or you can modify the accumulator to do the arithmetic:

count_leaves(Tree, Count) :-
    count_leaves(Tree, 0, Count).

count_leaves(leaf(_), Count0, Count) :-
    Count is Count0 + 1.
count_leaves(node(Left, Right), Count0, Count) :-
    count_leaves(Left, Count0, Count1),
    count_leaves(Right, Count1, Count).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Willem Van Onsem
Solution 2
Solution 3 Peter Ludemann