Prolog谓词树中的单个节点

Prolog谓词树中的单个节点,prolog,Prolog,编写一个谓词,该谓词查找树中仅有一个子节点的所有节点。 考虑到这棵树 treeEx(X) :- X = t(73,t(31,t(5,nil,nil),nil),t(101,t(83,nil,t(97,nil,nil)),nil)). 它应该返回L=[31,101,83] 我尝试了以下操作,但它返回所有节点。我不知道如何只列出单个子节点 single(nil,[]). single(t(X,L,R),[X|S]) :- append(SL,SR,S), single(L,SL)

编写一个谓词,该谓词查找树中仅有一个子节点的所有节点。 考虑到这棵树

treeEx(X) :-
    X = t(73,t(31,t(5,nil,nil),nil),t(101,t(83,nil,t(97,nil,nil)),nil)).

它应该返回
L=[31,101,83]

我尝试了以下操作,但它返回所有节点。我不知道如何只列出单个子节点

single(nil,[]).
single(t(X,L,R),[X|S]) :- 
   append(SL,SR,S), single(L,SL), single(R,SR). 
[…]查找树中所有节点的谓词,其中只有一个子节点

首先考虑您感兴趣的案例:

single(t(V, nil, R), [V|Vr]) :- single(R, Vr).
single(t(V, L, nil), [V|Vl]) :- single(L, Vl).
  • t(V,nil,R)
    :=具有值
    V
    和单个(右)子节点
    R
    的节点
  • t(V,L,nil)
    :=具有值
    V
    的节点和单个(左)子节点
    L
然后想想其他你不感兴趣的案例(尽可能笼统):

  • t(V,nil,nil)
    :=具有值
    V
    且没有子节点的节点
  • t(V,L,R)
    :=具有值
    V
    和左(
    L
    )和右(
    R
    )子节点的节点
接下来想想你想“做什么”:在列表中收集你感兴趣的案例的值。因此,当您有感兴趣的案例时,您需要将值
V
添加到结果列表中:

[V|RestResults] % whatever RestResults is, not important atm
这样,您就可以编写谓词了:您知道它有一个“输入”参数(树)和一个“输出”参数(列表)。首先是您感兴趣的案例:

single(t(V, nil, R), [V|Vr]) :- single(R, Vr).
single(t(V, L, nil), [V|Vl]) :- single(L, Vl).
将值
V
添加到从单个子分支获得的结果(值列表)中

接下来是你不感兴趣的案例。首先,简单一点:

single(t(_,nil,nil), []).
这是一个叶节点(没有子节点)。它的值不有趣,并且没有可能来自其子级的结果,因此结果列表是空列表

最后,最复杂的情况是:

single(t(_, L, R), X) :- single(L, Vl), single(R, Vr), append(Vl, Vr, X).
两个孩子;在本例中,该值并不有趣,但子节点很有趣:您需要收集它们的结果列表并附加它们以创建此节点的结果列表

现在,在Prolog中,编写这些规则的顺序通常很重要,但在这种情况下,顺序并不重要(当Prolog对一个节点使用“错误”的规则时,例如最后一个-两个子-对于
t(\u0,nil,nil)
,那么它很快就会出现一种情况-
single(nil,\u0)
-没有规则匹配,并返回到“正确”规则)。尽管如此,我还是会根据其模式的“具体程度”对规则进行排序:首先是不允许有孩子的规则,然后是一个孩子两个,最后是两个孩子一个


(在ideone上)

单个子节点的条件是什么?是不是右边的不是
nil
但左边不是,反之亦然?您的代码不会在任何地方强制执行该条件。