簡體   English   中英

在Java中實現圖形時出錯

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM