在 Prolog 中的 is_a() 树中查找叶节点

Posted

技术标签:

【中文标题】在 Prolog 中的 is_a() 树中查找叶节点【英文标题】:Finding leaf nodes in is_a() Tree in Prolog 【发布时间】:2019-04-01 20:14:25 【问题描述】:

我在“prolog”中使用“is_a(X, Y)”制作了一个基本上是“树”。看起来像这样:

is_tree('b', 'a').
is_tree('c', 'a').
is_tree('d', 'b').
is_tree('e', 'b').
is_tree('f', 'c').
is_tree('g', 'c').

       a
  b         c
d   e      f  g

现在我正在尝试查找所有叶节点,即d, e, f, g。 到目前为止,我已经成功地将write()'ing 从第一片叶子中取出,但我不明白我应该如何回到树上找到其他节点,以及我应该如何写我的closing clause 来查找值。

find_leaf(X, Y):-
    \+is_tree(X, Y).
find_leaf(X, Y):-
    is_tree(A, Y), !,
    find_leaf(Y, A).
find_leaf(X, Y):-
    is_tree(A, X),
    write(Y),
    find_leaf(Y, A).

我怎样才能“再次备份”以找到其他叶子?什么是正确的“结束语”?

【问题讨论】:

XY 在这里做什么? 好吧,我没有命名它们,但它们可以是任何东西。这只是我用来寻找叶子的东西。其中一个是无关紧要的,但我无法弄清楚如何做到这一点,所以我采用了更多变量,希望对我有所帮助。 但我认为这有点错误。通常,您定义谓词,其中变量具有特定的含义,然后您的目标是通过调用带有这些变量的谓词来实现谓词的“主体”,使其与该目的一致。 最初我认为这可以通过仅使用 root 来解决,但是我仍然卡住了。 这里的root 是什么? 【参考方案1】:

Prolog 中的大多数谓词都不是write/1 的东西。就像在命令式和函数式编程中,通常有大量函数计算事物,而其他函数则“通信”事物(通过写入控制台、更改用户界面等。

所以我建议构造一个谓词find_leaf(X) 将变量X 与叶子统一起来。由于 Prolog 的回溯机制,我们可以最终统一所有叶子。

is_tree/2谓词中获取节点

这里的节点——除非你没有提到这一点——只能通过分析is_tree/2 谓词获得,其中第一项是“孩子”,第二项是“父母”。我们知道,如果它是一个节点而不是父节点,那么它就是一个休假。由于没有其他机制来定义树,因此节点(很可能)是某个 is_tree 谓词中的子节点。

因此,我们可以实现一个谓词来查找具有以下条件的子节点:

find_leave(X) :-
    is_tree(X, _),
    \+ is_tree(_, X).

所以第一次调用 is_tree(X, _) 会将 X 与树中的一个孩子统一起来,而第二个调用会验证 X 没有孩子。

然后产生:

?- find_leave(X).
X = d ;
X = e ;
X = f ;
X = g.

从给定的根中获取叶子

我们也可以通过参数传递根,例如:find_leave(b, X) 将统一Xb 的所有子代。我们这里做两种情况:

    R,根,不是父级,在这种情况下R = XR 是一个离开);和 否则,如果有孩子,我们递归调用find_leave(C, X)C 一个孩子。由于回溯,最终我们将获得所有叶子。

所以:

find_leave(R, R) :-
    \+ is_tree(_, R).
find_leave(R, X) :-
    is_tree(C, R),
    find_leave(C, X).

然后我们得到不同的根,不同的叶子:

?- find_leave(a, X).
X = d ;
X = e ;
X = f ;
X = g ;
false.

?- find_leave(b, X).
X = d ;
X = e ;
false.

?- find_leave(R, X).
R = a,
X = d ;
R = a,
X = e ;
R = a,
X = f ;
R = a,
X = g ;
R = b,
X = d ;
R = b,
X = e ;
R = c,
X = f ;
R = c,
X = g ;
false.

【讨论】:

看第一个答案我想我可能没有正确理解序言。 find_leave(X) 如何找到所有叶子并再次调用自己而不递归? @kataroty:它枚举了 is_tree(X, _). 谓词,因此 X 最终将与树中的 all 子节点统一(这些子节点也可以是 inode),但是那么我们的\+ is_tree(_, X) 就满足了,因为X 不存在child 很抱歉再次打扰您,如果您很忙,请忽略我,但是使用这种方法无法计算我们有多少叶子对吗? @kataroty:有,你只要在findall/3中使用它,然后计算长度,所以findall(L, find_leave(L), Ls), length(Ls, N)会统一N和叶子的数量。

以上是关于在 Prolog 中的 is_a() 树中查找叶节点的主要内容,如果未能解决你的问题,请参考以下文章

Prolog中的反向查找? (我如何找到关于 X 的所有真实情况?)

带有先决条件的 Prolog 路径查找

B+树介绍

在prolog中查找图节点之间的距离

Prolog中定义图:边和路径,查找两个顶点之间是不是有路径

使用“Prolog in Scala”查找可用的类型类实例