在Prolog上计算二叉树中的节点数?

在Prolog上计算二叉树中的节点数?,prolog,binary-tree,Prolog,Binary Tree,我有一些密码 tree1(tree(1, tree(2, tree(3,nil,nil), tree(4,nil,nil)), tree(5, tree(6,nil,nil), tree(7,nil,nil)) ) ). rbt_count_nodes(e,0):-!. rbt_count_node

我有一些密码

tree1(tree(1,
            tree(2,
                tree(3,nil,nil),
                tree(4,nil,nil)),
            tree(5,
                tree(6,nil,nil),
                tree(7,nil,nil))
        )
    ).
rbt_count_nodes(e,0):-!.
rbt_count_nodes(t(_,L,R),N):-
    rbt_count_nodes(L,NL),
    rbt_count_nodes(R,NR),
    N=NL+NR+1.

?-tree1(T),rbt_count_nodes(T,N),write(N).
但进球总是没有。为什么

rbt_count_nodes(t(_,L,R),N)
应该成为

rbt_count_nodes(tree(_,L,R),N)
N is NL + NR + 1
rbt_count_nodes(nil,0).

应该成为

rbt_count_nodes(tree(_,L,R),N)
N is NL + NR + 1
rbt_count_nodes(nil,0).
(=)/2
用于执行统一,
(is)/2
用于执行算术)

应该成为

rbt_count_nodes(tree(_,L,R),N)
N is NL + NR + 1
rbt_count_nodes(nil,0).

在这三次编辑之后应该没问题,尽管我无法测试,因此可能会被证明是错的。

在另一个答案中给出的注释旁边(使用
is/2
而不是
=/2
以及术语t->tree和e->empty的名称中的打字错误),应该考虑使用累加器来允许Prolog系统执行尾部递归:

rbt_count_nodes(T,N):-
  rbt_count_nodes(T, 0, N).

rbt_count_nodes(nil,N, N):-!.
rbt_count_nodes(tree(_,L,R),C,N):-
    succ(C, C1),
    rbt_count_nodes(L,C1,NL),
    rbt_count_nodes(R,NL,N).
过程
rbt\u count\u nodes/2
仅调用
rbt\u count\u nodes/3
,第二个参数为零(累加器)。在每个递归步骤中,该累加器都会递增1并执行递归。基本情况只是将累加器与输出统一起来,允许系统执行尾部递归并节省堆栈空间

[编辑]

根据注释,要使其真正成为尾部递归(即所有递归调用都是尾部调用),您可以向rbt_count_nodes/3添加一个新子句(并修改另一个):


使用这种方法,第一个子句处理一个空节点,第二个子句处理树的左侧,它只是将分支“移动”到当前节点的右侧,第三个子句只计算节点数。

对此,我只能补充一点,Prolog数据是符号的,Prolog统一是符号数据的结构统一;而
is
在假设参数表达式描述算术实体的情况下强制参数表达式。您可以随时在以下位置进行测试:)这段代码不是尾部递归的。您不需要剪切,因为
nil
树(,,,)
是互斥的选择。@Will Ness:这段代码是尾部递归的,为什么不这样说?。我刚刚修改了操作码,所以我留下了切口。@Mog:关于变量名,你说得对。改了那个名字!它不是尾部递归的,因为谓词在最后一条指令之前调用自己(即使最后一条指令也是对istelf的调用)。这意味着Prolog必须保存上下文,这与尾部递归方法不同。我认为它在技术上是尾部递归的,因为在最后一次递归调用时,它将丢弃上下文。但是,您是对的,对其本身的第一个递归调用确实需要retain上下文。