Prolog与facts数据库

Prolog与facts数据库,prolog,binary-tree,Prolog,Binary Tree,我正在学习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,

我正在学习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
?- check_tree(c4,c2).
false

?-check_tree(d1,b3).
true
定义谓词父/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
,但是我有两个问题。一个是返回一个列表,我想得到一个数字或false。第二个是,如果必须使用递归,我不知道如何找到基本情况

我认为我需要使用一些谓词,比如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
的谓词。该谓词检查一棵树是否是另一棵树的子树。例如:

?-father(3,a4,P).
P=7
?-father(6,a4,P).
false
?- 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的提示和耐心


无论如何,感谢您阅读此问题。

您不需要自己在树中搜索-您已经在数据库中将其分解为多个部分(节点)。Prolog将为您搜索它

你已经有了

父1(3,a4,P):-%第一近似值 P=7。
这是谓词的第一个近似值。请尝试:

-父亲1(3,a4,7)。
正确。
-父亲(6,a4,P)。

没错!但事实也是如此

父2(3,a4,P):-%二次近似值 树(c2,3,无,d2), (树(b3,7,c1,c2);树(b3,7,c2,c1)), P=7。 因此,也

父3(3,a4,P):-%三次近似值 树(C2,3,无,D2), (树(B3,P,C1,C2);树(B3,P,C2,C1))。 你知道我要说什么吗

两条评论。首先,为什么要使用这种表示法,而不仅仅是作为一个术语?你们的树中是否有共享的分支?循环

第二,
a4
在这里没有使用。你为什么需要它呢?你是否设想在你的树中有重复项,并想将你的搜索限制在一个子树上

但是,如果这不是您的疏忽,并且您确实希望限制您的搜索,那么您可以扩展上面的
father/3
谓词,将其用作构建块:继续搜索父亲,直到找到您正在搜索的父亲(即本例中的
a4
),或者不搜索(也就是说,在你上升的过程中没有遇到它,这意味着你在树的错误部分)。你需要调整它,不仅要找到值,还要找到父亲的ID(添加第四个参数)


编辑:以下是您可以采取的措施:

父4(三,A4,P,B3):-%第四近似值 树(C2,三,零,D2), (树(B3,P,C1,C2);树(B3,P,C2,C1))。 然后,如果你对扩展的
father4/4
谓词w.r.t.的第四个参数进行传递闭包,那么它就简单到

在1(3,a4)下:
可传递的\u闭包(父4(3,a4,\u),\u ID列表),%伪代码
memberchk(a4,ID列表)。

如果是<代码>真< /代码>,你就知道你在正确的子树中。你可以用手来编码连词,这是一个很好的练习,让你自己对语言和理论基础有一个真实的感受。考虑一个学徒在开始的时候必须先用手做每一项卑微的任务,然后才开始学习COM。快速完成工作的复杂工具。当然,总有一天一切都将由3D打印机完成,但在此之前(甚至在此之前),我们可以将我们的贸易视为一门艺术

但是手工编码也让您有机会提高效率,在找到父ID后立即停止搜索(如果找到):

在2(3,a4)下:-
父亲4(3,a4,P,B3),
(B3==a4,!%a剪裁,如果您愿意的话
;在(…,…).%递归调用下
用不同的名字来称呼它会有所帮助


注意递归:
3
a4
下,如果
a4
3
的父节点(在那里称为
B3
),或者
3
的父节点在
a4
下,这完全有道理,对吗?

一个节点只有一个“父节点”(除非您希望将整个链连接到根节点),所以
findall/3
在这里听起来不太合适。你父亲/3谓词的参数是什么意思?我理解
a4
是一个节点名,而
3
是一个节点值,但为什么在这个查询中两者都是?为什么不仅仅是节点名?你是如何从父亲那里得到
P=7
(3,a4,P)?
树(b3,7,c1,c2)
不是
a4
的父亲,但它是
c2
的父亲,它的值为3。这有点让人困惑…谢谢你的回答。父亲/3的参数是:父亲(我不想知道它的父节点,我要寻找的子树或树,节点的父亲)这篇文章的目标是在a4中搜索,这是一棵由b3、b4等子树组成的树。无论如何,我会在我的问题中编辑这篇文章,让它更清楚。在序言中,你会