我正在学习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
定义谓词父/ 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的提示和耐心。
非常感谢您阅读此问题。
答案 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
下,如果a4
是3
的父亲(在那里称为B3
),或如果3
的父亲在a4
之下。总的来说,对吧?