Prolog和事实数据库

时间:2017-06-09 17:38:26

标签: prolog binary-tree

我正在学习Prolog,我有一些问题要问你。我想学习如何解决这些问题,而不是最终解决方案。

作为一个新手,我对这门语言知之甚少,但我不想成为骗子:(

好的,我的问题是......

我已经定义了这样的二叉树:

tree(ID_of_tree,root,ID_left_tree,ID_right_tree)

例如,这棵树

enter image description here

定义如下

tree(a4,6,b3,b4).
tree(b3,7,c1,c2).
tree(c1,5,d1,nil).
tree(d1,1,nil,nil).
tree(c2,3,nil,d2).
tree(d2,4,nil,nil).
tree(b4,8,c3,c4).
tree(c3,10,nil,nil).
tree(c4,11,d3,d4).
tree(d3,9,nil,nil).
tree(d4,2,nil,nil).

它们是我的事实数据库中的事实。所以我的第一个问题是,如何在这个数据库中识别节点N的父亲。例如:

?-father(3,a4,P).
P=7
?-father(6,a4,P).
false

定义谓词父/ 3。

father(N,Abn,P).

N= Node that I want to get its father
Abn = Tree where Im looking for. If a4, this means that is the all tree in this case.
P = Father of N.

我正在考虑使用findall/3但是我有两个问题。一个这返回一个列表,我想得到一个数字或假。第二,如果必须使用递归,我不知道如何进入基本情况。

我认为我需要使用一些谓词,例如retract或asserta,但我不确定。

这是我的第一次尝试,但使用father(3,a4,P).的输出为false

father2(N,Abn,PA,PA):- =(N, PA).
father(N,Abn,P) :- tree(Abn,N,A1,_), tree(A1,PA,_,_), father2(N,A1,PA,P).
father(N,Abn,P) :- tree(Abn,N,_,A2), tree(A2,PA,_,_), father2(N,A2,PA,P).

我的第二次尝试就是这样,它会返回一个很好的解决方案

father(N,Abn,P):- tree(FT,N,_,_), tree(_,P,FT,_).
father(N,Abn,P):- tree(FT,N,_,_), tree(_,P,_,FT).

这可能很好,但我对此谓词有问题,例如

father(3,d3,P).
P = 7

如果我在查看子树

,我应该限制搜索树

好的,最后我明白了。这是我最终的尝试,并且像魅力一样工作。

首先,我创建了一个名为check_tree/2的谓词。此谓词检查树是否是其他树的子树。例如:

?- check_tree(c4,c2).
false

?-check_tree(d1,b3).
true

这是检查的代码:

check_tree(Abn1,Abn1).
check_tree(Ab1,Ab2):- tree(Ft,_,Ab1,_), check_tree(Ft,Ab2).
check_tree(Ab1,Ab2):- tree(Ft,_,_,Ab1), check_tree(Ft,Ab2).

然后我将这样的谓词父/ 3定义为:

father(N,Abn,P):- tree(FT,N,_,_), tree(_,P,FT,_), check_tree(FT,Abn).
father(N,Abn,P):- tree(FT,N,_,_), tree(_,P,_,FT), check_tree(FT,Abn).

现在我只计算父节点,如果节点在搜索子树内。

?- father(3,b3,P).
P=7

?- father(3,c4,P).
false

特别感谢luker和Will ness的提示和耐心。

非常感谢您阅读此问题。

1 个答案:

答案 0 :(得分:3)

您不需要自己在树中搜索 - 您已经将它归结为数据库中的碎片(节点)。 Prolog会为你搜索。

你已经拥有

father1(3, a4, P):-             % first approximation
    P = 7.

这是谓词的第一个近似值。试试吧:

  

? - father1(3,a4,7)。
  是的。
  ? - 父亲(6,a4,P)。
  假。

正确!但情况也是如此

father2(3, a4, P):-              % second approximation
    tree(c2,3,nil,d2), 
    ( tree(b3,7,c1,c2) ; tree(b3,7,c2,c1) ), 
    P = 7.

等等,也是

father3(3, a4, P):-               % third approximation
    tree(C2, 3, Nil, D2), 
    ( tree(B3, P, C1, C2) ; tree(B3, P, C2, C1) ).

你知道我要去哪儿吗?

两个评论。首先,为什么这种表示,而不仅仅是一个术语?你的树木会在其中共享分支吗?周期?

其次,此处未使用a4。为什么你需要它?您是否设想在树中重复,并希望限制搜索到子树?

但是,如果这不是您的疏忽,并且您确实想要约束搜索,则可以扩充上述father/3谓词以用作此构建块:继续搜索父亲,直到你找到你正在寻找的那个(在这种情况下是a4) - 或者不是(即在你的路上没遇到它,意味着你在树的错误部分)。你需要调整它不仅要找到值,还要找到父亲的ID(向它添加第四个参数)。

编辑:以下是您可以采用的方法:

father4(Three, A4, P, B3):-               % fourth approximation
    tree(C2, Three, Nil, D2), 
    ( tree(B3, P, C1, C2) ; tree(B3, P, C2, C1) ).

然后,如果你形成了扩展的father4/4谓词w.r.t的传递闭包。它的第四个论点,就像

一样简单
is_under1(3, a4):- 
    transitive_closure(father4(3, a4, _), List_Of_IDs),      % pseudocode
    memberchk(a4, List_Of_IDs).

然后如果它是true,你知道你在正确的子树中。你可以手工编写连词,这是一个很好的练习,让你自己真正感受到语言和理论基础。考虑一个学徒必须首先手动完成每个琐事,当他们开始时,然后继续学习更快地完成工作的复杂工具。当然,有一天将会有3D打印机完成所有工作,但在此之前(或甚至那时),我们可以尽情地将我们的贸易视为艺术。

但是手动编码让你有机会提高效率,一旦找到父ID就停止搜索(如果它 实测值):

is_under2(3, a4):-
    father4( 3, a4, P, B3),
    ( B3 == a4 , !                   % a cut, if you would like it
    ; is_under( ... , ... ) ).       % recursive call

以不同的名称调用它有帮助。

请注意递归:3位于a4下,如果a43的父亲(在那里称为B3),如果3的父亲在a4之下。总的来说,对吧?