【问题标题】:Prolog and facts databaseProlog 和事实数据库
【发布时间】:2017-06-09 17:38:25
【问题描述】:

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

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

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

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

tree(ID_of_tree,root,ID_left_tree,ID_right_tree)

例如,这棵树

是这样定义的

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

定义谓词father/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). 的输出是错误的

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).

接下来我像这样定义谓词father/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 的提示和耐心。

感谢您阅读此问题。

【问题讨论】:

  • 一个节点只有一个“父亲”(除非您希望整个链都指向根节点),所以findall/3 在这里听起来不合适。 father/3 谓词的参数是什么意思?我理解 a4 是一个节点名称,3 是一个节点值,但为什么在这个查询中两者都有?为什么不只是节点名称?你是如何从father(3, a4, P) 得到P=7 的? tree(b3, 7, c1, c2) 不是 a4 的父亲,但它是 c2 的父亲,其值为 3。这有点令人困惑......
  • 感谢您的回复。父亲/3 的参数是:父亲(节点比我想知道它的父节点,我要寻找的子树或树,节点的父亲)。这样做的目标是在 a4 中搜索,这是一棵由 b3、b4..etc 等子树组成的树。无论如何,我会在我的问题中编辑它以使其更清楚。
  • 在 Prolog 中,您通常会使用递归。由于您没有尝试解决此问题,因此我不会为您编写代码,但我可以给您一些提示。一种简单的方法是使用辅助谓词:father(Node, Tree, FatherNode, Father)FatherNode 是当前候选父节点)。最初,FatherNode 具有由初始 father/3 调用给出的节点的值。不要使用retractasserta
  • 感谢您的回复!这是我第一次尝试使用递归,但给了我错误。我用这个尝试编辑了我的问题:father2(N,Abn,PA,PA):- =(N, PA)。父亲(N,Abn,P):-树(Abn,N,A1,),树(A1,PA,),父亲2(N,A1,PA,P)。父亲(N,Abn,P):-树(Abn,N,,A2),树(A2,PA,),父亲2(N,A2,PA,P) .
  • 您想要一个提示,帮助您学习如何自己编写代码。现在您需要特定代码的帮助吗?这是两个不同的问题。我回答了你原来的那个。

标签: prolog binary-tree


【解决方案1】:

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

你已经有了

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

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

?- 父亲1(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

用不同的名字来称呼它会有所帮助。

注意递归:如果a43 的父亲(那里称为B3),则3a4 之下, 如果3 的父亲在a4 下。完全有道理,对吧?

【讨论】:

  • 该操作使用a4father 的第二个参数)来选择查询所考虑的最顶层树/子树。所以答案不应该涉及树的任何部分高于/超出该点。
  • @lurker 我在答案中解决了这个问题。无论如何,他们要求提示,所以这是一个开始。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多