我已经看过有关深度优先搜索的其他问题,但我的问题略有不同,我真的不明白。 在prolog中,我代表我的无向图:
HBox
这是一组键值,其中键表示节点和列表:import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
private static VBox mainPane;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
mainPane = new VBox(5);
mainPane.setPadding(new Insets(10));
mainPane.setAlignment(Pos.TOP_CENTER);
mainPane.getChildren().add(new UIForms());
primaryStage.setScene(new Scene(mainPane));
primaryStage.show();
}
static void addField() {
mainPane.getChildren().add(new UIForms());
}
static void removeField(UIForms field) {
if (mainPane.getChildren().size() > 1) {
mainPane.getChildren().remove(field);
}
}
}
class UIForms extends HBox {
private TextField textField1;
private TextField textField2;
private Button btnAddField;
private Button btnRemoveField;
public UIForms() {
// Setup the HBox layout
setAlignment(Pos.CENTER_LEFT);
setSpacing(5);
// Create the UI controls
textField1 = new TextField();
textField2 = new TextField();
btnAddField = new Button("+");
btnRemoveField = new Button("-");
// Setup button actions
btnAddField.setOnAction(e -> Main.addField());
btnRemoveField.setOnAction(e -> Main.removeField(this));
// Add the UI controls
getChildren().addAll(
textField1, textField2, btnAddField, btnRemoveField
);
}
}
表示其邻居。
我不知道如何使用此模型进行深度优先搜索。我尝试了很多解决方案。我想要一个非常基本的递归算法,如下所示:
[0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]]
我无法在prolog中做的是作为可变引用访问的传递,它将被每个邻居递归修改为下一个邻居。
因为如果我把它翻译成prolog:
-[]
我需要某种折叠,每个邻居都会调用dfs并将其结果传递给下一个邻居,但我不知道如何做到这一点......
感谢。
答案 0 :(得分:1)
直接将您的代码翻译成Prolog。不要过分思考它;说出你的意思:
/* dfs(v, visited):
if visited[v] then return
visited.insert(v)
foreach neighbor of v:
dfs(neighbor, visited) */
dfs(Graph, V, Visited, Return) :-
visited(V, Visited),
return(Graph, V, Visited, Return).
dfs(Graph, V, Visited, Return) :-
\+ visited(V, Visited),
appended(Visited, [V], Visited2),
neighbor(Graph, V, N),
dfs(Graph, N, Visited2).
谓词visited/2
,return/4
,appended/3
,neighbor/3
应该很容易实现。
首先是正确性,以后是效率。
答案 1 :(得分:0)
传统的DFS算法涉及递归和堆栈,它基本上是一种回溯机制。在Prolog中,如果你想要积累"如果您需要的元素是在回溯中获得的,那么列表可能具有挑战性。
以下代码是DFS搜索的非常简单的呈现,并将在DFS搜索中写出节点:
dfs(Graph, StartNode) :-
dfs(Graph, StartNode, []).
dfs(Graph, Node, Visited) :-
\+ member(Node, Visited),
member(Node-Neighbors, Graph),
write(Node), nl,
member(NextNode, Neighbors),
dfs(Graph, NextNode, [Node|Visited]).
两个member
调用看起来有点像你试图做的那样,但不完全一样。它们共同构成了这种结构的DFS遍历的关键。
查询这个你会得到:
| ?- dfs([0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]], 0).
0
1
2
3
5
yes
| ?-
但是,写出图中的节点并不是特别有用。我们想在列表中收集它们。可以修改上述内容,使其成为沿搜索路径成功的每个节点的谓词。
dfs(Graph, StartNode, Node) :-
dfs(Graph, StartNode, [], Node).
dfs(Graph, ThisNode, Visited, Node) :-
\+ member(ThisNode, Visited),
( Node = ThisNode % Succeed finding a new node
; member(ThisNode-Neighbors, Graph), % Or... find the next node
member(NextNode, Neighbors),
dfs(Graph, NextNode, [ThisNode|Visited], Node)
).
这导致:
| ?- dfs([0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]], 0, Node).
Node = 0 ? a
Node = 1
Node = 2
Node = 3
Node = 5
no
| ?-
现在您可以使用findall/3
将节点作为列表获取:
dfs_path(Graph, StartNode, Nodes) :-
findall(Node, dfs(Graph, StartNode, Node), Nodes).
现在你可以写:
| ?- dfs_path([0-[1,5], 1-[0,2], 2-[1,3], 3-[2,0], 5-[0]], 0, Nodes).
Nodes = [0,1,2,3,5]
yes
| ?-