【发布时间】:2020-04-01 22:48:36
【问题描述】:
我正在尝试对给定图执行迭代广度优先遍历、迭代深度优先遍历和递归深度优先遍历(使用邻接矩阵)。
在当前状态下,我的程序会输出各种错误答案。
这里有一些例子。
我期待
From Node A
DFS (iterative): A B H C D E I F G
DFS (recursive): A B H C D E I F G
BFS (iterative): A B D I H C E F G
但我却得到了
From Node A
DFS (iterative): A I D B H C F G E
DFS (recursive): A B H C F D E I G
BFS (iterative): A B D I H C E F G
我不确定我的程序的问题在于遍历的实现,还是我对程序其他部分的实现。更具体地说,我不确定我的实现 connectNode 或 getNeighbors 方法是导致错误输出的原因,还是我的遍历实现。
编辑:如果这很重要,应该按升序选择邻居。也许这是问题的一部分?
EDIT2:感谢@HylianPikachu 的建议,我添加了新的代码行。我现在得到了完整的答案,但它们的顺序仍然不正确。
EDIT3:我添加了代码,以便检查根节点是否已访问 bfs 和递归 dfs。我认为。我还应该注意,我得到了这段代码的一部分,并被告知要填写其余部分。我被告知要使用堆栈和队列,即使可能有更好的选择。
EDIT4:添加了建议的内容,现在,迭代 BFS 可以工作并获得正确的结果。但是,两个 DSF 搜索仍然不起作用。我修改了上面程序的结果,以显示这一点。
import java.util.*;
public class GraphM {
public Node rootNode;
public List<Node> nodes = new ArrayList<Node>(); // nodes in graph
public int[][] adjMatrix; // adjacency Matrix
public void setRootNode(Node n) {
rootNode = n;
}
public Node getRootNode() {
return rootNode;
}
public void addNode(Node n) {
nodes.add(n);
}
// This method connects two nodes
public void connectNode(Node src, Node dst) {
if(adjMatrix == null) {
adjMatrix = new int[nodes.size()][nodes.size()];
}
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;
}
// Helper method to get one unvisited node from a given node n.
private Node getUnvisitedChildNode(Node n) {
int index = nodes.indexOf(n);
int size = adjMatrix.length;
for (int j = 0; j < size; j++)
if (adjMatrix[index][j] == 1 && ((Node) nodes.get(j)).visited == false)
return nodes.get(j);
return null;
}
// get all neighboring nodes of node n.
public List<Node> getNeighbors(Node n) {
List<Node> neighbors = new ArrayList<Node>();
for(int i = 0; i < nodes.size(); i ++) {
if (adjMatrix[nodes.indexOf(n)][i] == 1) {
neighbors.add(nodes.get(i));
}
Collections.sort(neighbors);
}
return neighbors;
}
// Helper methods for clearing visited property of node
private void reset() {
for (Node n : nodes)
n.visited = false;
}
// Helper methods for printing the node label
private void printNode(Node n) {
System.out.print(n.label + " ");
}
// BFS traversal (iterative version)
public void bfs() {
Queue<Node> queue = new LinkedList<Node>();
queue.add(rootNode);
while(!queue.isEmpty()) {
Node node = queue.poll();
printNode(node);
node.visited = true;
List<Node> neighbors = getNeighbors(node);
for ( int i = 0; i < neighbors.size(); i ++) {
Node n = neighbors.get(i);
if (n != null && n.visited != true) {
queue.add(n);
n.visited = true;
}
}
}
}
// DFS traversal (iterative version)
public void dfs() {
Stack<Node> stack = new Stack<Node>();
stack.add(rootNode);
while(!stack.isEmpty()){
Node node = stack.pop();
if(node.visited != true) {
printNode(node);
node.visited = true;
}
List<Node> neighbors = getNeighbors(node);
for (int i = 0; i < neighbors.size(); i++) {
Node n = neighbors.get(i);
if(n != null && n.visited != true) {
stack.add(n);
}
}
}
}
// DFS traversal (recursive version)
public void dfs(Node n) {
printNode(n);
n.visited = true;
List<Node> neighbors = getNeighbors(n);
for (int i = 0; i < neighbors.size(); i ++) {
Node node = neighbors.get(i);
if(node != null && node.visited != true) {
dfs(node);
}
}
}
// A simple Node class
static class Node implements Comparable<Node> {
public char label;
public boolean visited = false;
public Node(char label) {
this.label = label;
}
public int compareTo(Node node) {
return Character.compare(this.label, node.label);
}
}
// Test everything
public static void main(String[] args) {
Node n0 = new Node('A');
Node n1 = new Node('B');
Node n2 = new Node('C');
Node n3 = new Node('D');
Node n4 = new Node('E');
Node n5 = new Node('F');
Node n6 = new Node('G');
Node n7 = new Node('H');
Node n8 = new Node('I');
// Create the graph (by adding nodes and edges between nodes)
GraphM g = new GraphM();
g.addNode(n0);
g.addNode(n1);
g.addNode(n2);
g.addNode(n3);
g.addNode(n4);
g.addNode(n5);
g.addNode(n6);
g.addNode(n7);
g.addNode(n8);
g.connectNode(n0, n1);
g.connectNode(n0, n3);
g.connectNode(n0, n8);
g.connectNode(n1, n7);
g.connectNode(n2, n7);
g.connectNode(n2, n3);
g.connectNode(n3, n4);
g.connectNode(n4, n8);
g.connectNode(n5, n6);
g.connectNode(n5, n2);
// Perform the DFS and BFS traversal of the graph
for (Node n : g.nodes) {
g.setRootNode(n);
System.out.print("From node ");
g.printNode(n);
System.out.print("\nDFS (iterative): ");
g.dfs();
g.reset();
System.out.print("\nDFS (recursive): ");
g.dfs(g.getRootNode());
g.reset();
System.out.print("\nBFS (iterative): ");
g.bfs();
g.reset();
System.out.println("\n");
}
}
}
【问题讨论】:
-
我只进行了扫描,所以问题很可能出在其他地方,但我想知道您是否会遇到问题,因为您使用
adjMatrix[indexOf(src)][indexOf(dst)] = 1连接节点,但也不是使用@987654325 @ .在处理图表时,我会同时执行这两项任务,因此无论何时我搜索邻居时首先调用哪个顶点都无关紧要。 -
酷,成功了!我要指出的第二件事是,当我们最初将根节点添加到 bfs 中的队列时,我们没有将根节点设置为已访问,并且在递归版本的 dfs 中也会出现类似的问题。事实上,在我看来,递归 dfs 中没有任何节点被标记为已访问。 (这与订购无关,但这些仍然很重要。)
-
尽量不要在connectNode内部初始化adjMatrix,把它放到构造函数中,这样你的类的逻辑就更容易了。
-
澄清问题:您想要达到的顺序到底是什么?当您使用队列和堆栈时,您对排序的控制很少,因此如果您需要对数据进行排序,可能需要使用不同的数据结构。
-
@HylianPikachu 每当给定相邻节点的列表时,节点应按键的升序排列。 (最小的节点总是第一个)。或者,如果一个节点与其他三个节点有连接,它会选择最小的节点先去。
标签: java graph-theory depth-first-search graph-traversal