Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于Prolog的图循环检测_Prolog - Fatal编程技术网

基于Prolog的图循环检测

基于Prolog的图循环检测,prolog,Prolog,我正试图编写一个prolog程序来检测无向图中的循环。 我已经咨询过这个问题: 并试图改变dfs算法,以检测周期。 以下是我目前的进展: findCycle(Node, NextNode, Visited) :- ( member(NextNode, Visited), isNotParent(Node, NextNode) ) -> writeln("found a cycle"), saveCycle(Node, NextNode),

我正试图编写一个prolog程序来检测无向图中的循环。 我已经咨询过这个问题:

并试图改变dfs算法,以检测周期。 以下是我目前的进展:

findCycle(Node, NextNode, Visited) :-
      ( member(NextNode, Visited), isNotParent(Node, NextNode) )
    ->
      writeln("found a cycle"), saveCycle(Node, NextNode), !
    ;
      writeln("end of findCycle").
   
saveCycle(Node, NextNode) :-
    % save to structure
 
dfs(Graph, StartNode) :-
    dfs(Graph, StartNode, []).

dfs(Graph, Node, Visited) :-
    writeln(Visited),
    \+ member(Node, Visited),
    write("visiting node "),
    write(Node), nl,
    member(NextNode, Graph.get(Node)),
    % \+ findCycle(Node, NextNode, Visited),
    dfs(Graph, NextNode, [Node|Visited]).
我的实现中的图将表示为一个字典,其中每个键都是一个顶点,对应的值是其所有相邻顶点的列表。 现在,我有几个问题:

  • 我需要将每个顶点的“父节点”存储在数据结构中,以便用于周期检测。我不知道该怎么做。到目前为止,我一直在用一个示例图测试这个程序,我用单个术语手动输入它的边。然而,这不是我的最终目标

  • 我还需要修复dfs算法,因为它现在会导致堆栈溢出,因为访问列表不会持久存储所有顶点。理想情况下,访问应该是一个字典而不是一个列表,这样可以更有效地访问它

  • 最后,如果检测到循环,我想将参与循环的所有顶点保存到另一个数据结构中


虽然我知道编程,并且在过去已经用C++编写了这个程序,但是我对PROlog的理解是最好的,所以任何帮助都会被理解的。谢谢

你有点过度工程化了

只要把你的代码简化到最需要的程度,你就会得到你想要的。。。例如:

find_循环(G,Vs):-
成员(V-_边,G),%不关心起点
求循环(G,V,[],Vs)。
查找循环(_G,V,SeenVs,[V | SeenVs]):-
成员(V,见NVS)。
查找循环(G,V,见NVS,循环):-
\+成员(V,见NVS),
成员(V-Es,G),
成员(Ve、Es),
求循环(G,Ve,[V | SeenVs],循环)。
?-G=[a-[b,c],b-[a,c],c-[],求循环(G,c)。
G=[a-[b,c],b-[a,c],c-[],
C=[a,b,a];
G=[a-[b,c],b-[a,c],c-[],
C=[b,a,b];
错。
或者,为避免在“已访问边”列表中重复搜索:

find_循环(G,V,见NVS,循环):-
(成员CHK(V,见NVS)
->循环=[V |见NVS]
;成员(V-Es,G),
成员(Ve、Es),
求循环(G,Ve,[V | SeenVs],循环)
).
评论后编辑


为了提高效率,请注意,我在测试中使用了memberchk/2,而不是member/2。SWI Prolog中的实现速度非常快,因为它使用了列表的低级表示(
跳过列表
),是用C完成的。因此,在开始使用其他数据结构观察某些改进之前,您应该有很长的列表(有一些…如rbtrees、avltrees等)。但是如果你的列表太大,那么整个算法应该改进。同样,也有一些,您可以开始在library()中查找。

您有点过度工程化了

只要把你的代码简化到最需要的程度,你就会得到你想要的。。。例如:

find_循环(G,Vs):-
成员(V-_边,G),%不关心起点
求循环(G,V,[],Vs)。
查找循环(_G,V,SeenVs,[V | SeenVs]):-
成员(V,见NVS)。
查找循环(G,V,见NVS,循环):-
\+成员(V,见NVS),
成员(V-Es,G),
成员(Ve、Es),
求循环(G,Ve,[V | SeenVs],循环)。
?-G=[a-[b,c],b-[a,c],c-[],求循环(G,c)。
G=[a-[b,c],b-[a,c],c-[],
C=[a,b,a];
G=[a-[b,c],b-[a,c],c-[],
C=[b,a,b];
错。
或者,为避免在“已访问边”列表中重复搜索:

find_循环(G,V,见NVS,循环):-
(成员CHK(V,见NVS)
->循环=[V |见NVS]
;成员(V-Es,G),
成员(Ve、Es),
求循环(G,Ve,[V | SeenVs],循环)
).
评论后编辑


为了提高效率,请注意,我在测试中使用了memberchk/2,而不是member/2。SWI Prolog中的实现速度非常快,因为它使用了列表的低级表示(
跳过列表
),是用C完成的。因此,在开始使用其他数据结构观察某些改进之前,您应该有很长的列表(有一些…如rbtrees、avltrees等)。但是如果你的列表太大,那么整个算法应该改进。同样,还有一些,您可以开始在library()中查找。

谢谢您的回复,我想我明白了。是否有比
成员/2
更有效的方法来检查是否访问了顶点?问,因为我认为这将需要线性时间取决于列表的大小。好吧,我明白了!再次感谢,我将尝试一下!谢谢你的回复,我想我明白了。是否有比
成员/2
更有效的方法来检查是否访问了顶点?问,因为我认为这将需要线性时间取决于列表的大小。好吧,我明白了!再次感谢,我将尝试一下!