[英]Error in implementing a graph in Java
我正在尝试使用LinkedList的ArrayList在Java中创建图形。 我已经实现了自己的清单。 但是,当我尝试在图的顶点之间添加连接时,遇到了一个无限循环。 我正在调试,我意识到这是在尝试将元素添加到LinkedList末尾时发生的。 我是一个初学者,我看不到List实现有什么问题。 有人可以帮忙吗?
import java.util.Stack;
// traverse the graph
public class GraphTraversal {
public static void main(String[] args)
{
Graph graph=new Graph();
initializeGraph(graph);
graph.breadthFirstSearch();
}
public static void initializeGraph(Graph graph)
{
Node_Graph node1=new Node_Graph(1, false);
Node_Graph node2=new Node_Graph(2, false);
Node_Graph node3=new Node_Graph(3, false);
Node_Graph node4=new Node_Graph(4, false);
Node_Graph node5=new Node_Graph(5, false);
Node_Graph node6=new Node_Graph(6, false);
Node_Graph node7=new Node_Graph(7, false);
Node_Graph node8=new Node_Graph(8, false);
graph.addNode(node1);
graph.addNode(node2);
graph.addNode(node3);
graph.addNode(node4);
graph.addNode(node5);
graph.addNode(node6);
graph.addNode(node7);
graph.addNode(node8);
graph.makeConnection(node1, node2);
graph.makeConnection(node1, node3);
graph.makeConnection(node3, node4);
graph.makeConnection(node3, node5);
graph.makeConnection(node4, node5);
graph.makeConnection(node4, node6);
graph.makeConnection(node4, node8);
graph.makeConnection(node4, node2);
graph.makeConnection(node6, node5);
graph.makeConnection(node8, node7);
graph.makeConnection(node7, node2);
}
}
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
//Class for graph data structure
public class Graph {
public ArrayList<List> nodes=new ArrayList<List>();
public void addNode(Node_Graph n)
{
List new_node=new List();
new_node.add(n);
nodes.add(new_node);
}
public void makeConnection(Node_Graph node1, Node_Graph node2)
{
for(List list:nodes)
{
if(list.head.getId()==node1.getId())
{
list.add(node2);
break;
}
}
}
public void breadthFirstSearch()
{
Stack<Node_Graph> traverse=new Stack<Node_Graph>();
Node_Graph start=(nodes.get(0)).head;
start.setVisited(true);
traverse.push(start);
while(traverse.empty())
{
Node_Graph popped=traverse.pop();
System.out.println(popped.getId());
List nextList= nodes.get(popped.getId());
Node_Graph newElement=nextList.head;
while(newElement.getNext()!=null)
{
newElement=newElement.getNext();
if(!newElement.getVisited())
{
newElement.setVisited(true);
traverse.push(newElement);
}
}
if(!newElement.getVisited())
traverse.push(newElement);
}
}
}
//linked list implementation
public class List{
public Node_Graph head;
public int size;
public List()
{
head=null;
size=0;
}
public void add(Node_Graph element)
{
if(head==null)
{
head=element;
}
else
{
Node_Graph last=head;
while(last.getNext()!=null)
{
last=last.getNext();
}
last.setNext(element);
}
}
}
//node of a graph
public class Node_Graph {
private int id;
private boolean visited;
private Node_Graph next;
public Node_Graph(int id,boolean visited)
{
this.id=id;
this.visited=visited;
}
public void setId(int id)
{
this.id=id;
}
public int getId()
{
return id;
}
public void setVisited(boolean visited)
{
this.visited=visited;
}
public boolean getVisited()
{
return visited;
}
public void setNext(Node_Graph next)
{
this.next=next;
}
public Node_Graph getNext()
{
return next;
}
}
线图graph.makeConnection(node4, node6);
导致无限循环,因为节点4的下一个变量与节点5无限连接
我注意到的第一件事是线graph.makeConnection(node3, node5);
导致4连接到5,这是不应该的。
我将toString方法添加到您的列表和node_graph类中,以使其更容易理解正在发生的事情。 在这里,您可以尝试一下:
列表:
public String toString(){
Node_Graph h = head;
String s = "";
while(h != null){
s += "[" + h.toString() + "] ";
h = h.next;
}
return s;
}
Node_Graph:
public String toString(){
String s = id + "";
if(next != null)
s += ", " + next.toString();
return s;
}
跟踪错误。 让我们从这一行开始:
graph.makeConnection(node1, node3);
这会导致调用: {1 -> 2,2 -> null}.add(3)
到目前为止{1 -> 2,2 -> null}.add(3)
顺利。
另外,您将找到列表的最后一个元素:{2},并将其设置在{3}的旁边。 因此,列表现在看起来像{1-> 2-> 3,2-> 3,3},而列表应该是{1-> 2-> 3,2,3}。 第一个列表(错误地)表示1连接到2和3,2连接到3,而2不应该连接到3,如第二个列表所示。 在您当前的方案中,这是不可能的,因为“ 2”实际上是相同的对象,具有相同的,唯一的next
字段。 它不能是1元素中的{3},本身不能是{null}。
总体而言,您需要区分两个“下一个”。 我相信您的目标是,node_graph中的下一个字段表示该节点连接到的节点,而列表中的下一个字段表示列表中的下一个节点,无论是否存在连接。 您正在尝试在下一个字段中用一块石头获得两只鸟,然后又将其无限次递归给您。
实现图有许多更简洁的方法-哈希图(节点->邻居节点列表)更加简洁,使您无需处理所有下一项业务。 如果您的主要目标是完善图形算法(例如bfs / dfs-ing),则可能只想这样做。
但是,如果您确实想使用列表实现图,则需要进行一些整理。 我建议完全从Node_Graph类中删除next
字段。 Node_Graph类应该只担心自己的数据,而不要维护列表不变式。 然后,使列表类具有一个内部包装器类,该包装器类包含一个“ this”(一个Node_Graph实例)和一个“ next”(一个Node_Wrapper)实例。 完成所有这些操作后,您可以为您的Node_Graph提供一个List类型的邻居字段,该字段将保存其所有可访问的邻居。
这是遵循您的模式的基本HashMap图形实现。 您也不需要列表实现。 无需包装器/下一步:
public class Node{
public final Graph graph; //The graph this Node belongs to
private int id;
private boolean visited;
/** Constructs a Node with the given inputs.
* Also adds itself to g as part of construction */
public Node(Graph g, int i, boolean v){
graph = g;
id = i;
visited = v;
graph.addNode(this);
}
public int getId(){
return id;
}
public void setVisited(boolean v){
visited = v;
}
//Getters for boolean fields usually follow the is<Field> pattern
public boolean isVisited(){
return visited;
}
/** Looks up the neighbors of this in the graph */
public Set<Node> getNeighbors(){
return graph.neighborsOf(this);
}
}
public class Graph{
private HashMap<Node, HashSet<Node>> graph; //The actual graph. Maps a node -> its neighbors
public Graph(){
graph = new HashMap<Node, HashSet<Node>>();
}
/** Adds the node to this graph.
If n is already in this graph, doesn't overwrite */
public void addNode(Node n) throws IllegalArgumentException{
if(n.graph != this)
throw new IllegalArgumentException(n + " belongs to " + n.graph ", not " + this);
if(! graph.contains(n))
graph.put(n, new HashSet<Node>());
}
/** Returns the neighbors of the given node.
* Returns null if the node isn't in this graph */
public Set<Node> neighborsOf(Node n){
if(! graph.contains(n))
return null;
return graph.get(n);
}
/** Connects source to sink. Also adds both to graph if they aren't there yet */
public void makeConnection(Node source, Node sink){
//Make sure source and sink belong to this graph first
addNode(source);
addNode(sink);
//Make the connection by adding sink to source's associated hashset
graph.get(source).add(sink);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.