在无向图中查找和打印循环

时间:2017-10-26 16:32:58

标签: java graph-traversal

我正在进行一项任务,我需要在其中执行无向图的DFS,然后打印一个循环(如果找到一个循环)。问题是,我找到的任何寻找循环的算法都不存储循环 - 它们只是真/假。我目前的代码仅适用于某些图表,但不适用于其他图表。例如,它无法找到2节点周期(4-5,5-4)。此外,它只适用于现在指示它应该是无向的。

编辑:这不是关于查找和打印周期的其他问题的重复,因为据我所知,其他问题都没有解决如何存储和随后打印周期 - 只是如何查找是否如何查找它存在并返回true / false。

修改:格式化

附件是我的遍历代码和我的主要方法

- 主要方法

    public static void main(String args[]) {
//
//        Graph g = new Graph(8);
//
//        g.add(0, 2);
//        g.add(2, 3);
//        g.add(3, 1);
//        g.add(1, 0);
//
//        g.add(4, 5);
//        g.add(5, 6);
//        g.add(6, 7);
//        g.add(7, 4);
//

//        Graph g = new Graph(6);
//
//        g.add(0, 1);
//        g.add(1, 3);
//        g.add(2, 3);
//        g.add(3, 4);
//        g.add(3, 5);
//


//        Graph g = new Graph(7);
//
//        g.add(0, 1);
//        g.add(0, 2);
//        g.add(0, 3);
//        g.add(3, 4);
//        g.add(4, 3);
//        g.add(4, 5);
//        g.add(4, 6);


         Graph g = new Graph(5);


        g.add(0, 1);
        g.add(2, 3);
        g.add(2, 4);
        g.add(3, 4);





        DepthFirstTraversal dfs = new DepthFirstTraversal(g);

        System.out.println("Following is Depth First Traversal");

        dfs.DFS();

        if (!dfs.isCyclic())
            System.out.println("This graph is acyclic");

    }

- 图表类

import java.util.LinkedList;


public class Graph {

    //Number of Vertices
    private int vertices;

    //Linked List to hold edges
    private LinkedList<Integer> edges[];


    public Graph(int verticesGiven) {
        this.vertices = verticesGiven;
        this.edges = new LinkedList[vertices];
        fillNodes(edges, vertices);
    }


    private static void fillNodes(LinkedList<Integer> edges[], int 
    vertices) {
        for (int counter = 0; counter < vertices; ++counter) {
            edges[counter] = new LinkedList();
        }
    }


    void add(int x, int y) {
        edges[x].add(y);
    }

    public int getVertices() {
        return vertices;
    }


    public LinkedList<Integer>[] getEdges() {
        return edges;
    }

}

- 遍历和循环搜索

import java.util.*;


public class DepthFirstTraversal {

    //Each traversal has a graph
    private Graph graph;

    //Holds the nodes for each cycle
    private List<Integer> cycle = new ArrayList<Integer>();


    public DepthFirstTraversal(Graph graph) {

        this.graph = graph;
    }


    private void DFSRecursive(int current, boolean visited[], 
    LinkedList<Integer> edges[]) {

        // Say you visited current node
        visited[current] = true;

        //Print the current node
        System.out.print(current + " ");

        // Look at all vertices connected to this one
        Iterator<Integer> iterate = edges[current].listIterator();

        //Check to see everything this is connected to
        while (iterate.hasNext()) {

            //Check to see what the next one is
            int connected = iterate.next();

            //check if you've already visited what it's connected to. 
            If you haven't, check that one out.
            if (!visited[connected])

                //Check whatever the current one is connected to
                DFSRecursive(connected, visited, edges);
        }


    }

    public void DFS() {

        //Check to see how many vertices graph has
        int vertices = graph.getVertices();

        //Keeps track of which vertices have already been visited
        boolean visited[] = new boolean[vertices];

        //Visits all of the nodes
        for (int counter = 0; counter < vertices; ++counter)

            //calls recursive method if this node has not been visited
            if (!visited[counter])
                DFSRecursive(counter, visited, graph.getEdges());
    }

    private Boolean isCyclicRecursive(int index, Boolean visited[], int 
    parent, LinkedList<Integer> edges[]) {

        // Mark the current node as visited
        visited[index] = true;

        //Integer to hold what the node is connected to
        Integer connection;

        // Recur for all the vertices adjacent to this vertex
        Iterator<Integer> iterator = edges[index].iterator();

        //Check to see if the current node has a connection
        while (iterator.hasNext()) {

            //Looks at what is connected to it.
            connection = iterator.next();

            //If you haven't visited the connection, look at that. Sets the current as the parent of the connection.
            if (!visited[connection]) {
                cycle.add(index);
                if (isCyclicRecursive(connection, visited, index, 
              graph.getEdges())) {
                    return true;
                } else {
                    Integer item = new Integer(index);
                    cycle.remove(item);
                }
            }

            //Checks to see if the thing it's connected to is its parent (you've completed a cycle)
            else if (connection != parent) {

                //Add parent and connection
                cycle.add(index);
                cycle.add(connection);

                //Only find the things in current cycle
                for (int i = 0; i < cycle.size(); i++) {

                    //Not a true cycle
//                    if (cycle.size() <= 1)
//                        return false;

                    int first = cycle.get(i);
                    int last = cycle.get(cycle.size() - 1);

                    if (first == last) {
                        System.out.print("Cycle Detected: ");
                        for (int j = 0; j < cycle.size(); j++) {
                            System.out.print(cycle.get(j).toString() + " ");
                        }
                        System.out.println();
                        return true;
                    } else {
                        //only prints things actually in this cycle
                        cycle.remove(i);
                        i--;
                    }
                }
                return true;
            }
        }

        return false;
    }

    /**************************************************************/
    /* Method: isCyclic
    /* Purpose: Checks to see if graph is cyclic
    /* Parameters: None
    /* Returns: None
    /**************************************************************/
    public Boolean isCyclic() {

        //Mark all vertices as not visited
        int vertices = graph.getVertices();

        Boolean visited[] = new Boolean[vertices];

        for (int counter = 0; counter < vertices; counter++)
            visited[counter] = false;

        //For every node, check if it is cyclic
        for (int counter = 0; counter < vertices; counter++)

            //Only check for cyclic if this has been visited
            if (!visited[counter])
                if (isCyclicRecursive(counter, visited, -1, graph.getEdges()))
                    return true;

        return false;
    }

}

1 个答案:

答案 0 :(得分:1)

我有一个问题是,如果您的图表是无向的,您如何将4-5和5-4视为单独的边?对我来说,在无向图中,4-5和5-4是相同的边,因此不是循环。在有向图上,它们是不同的,因此形成一个循环。此外,图表数组长度为2的所有LinkedList个对象都是?如果您想要无向,则可以使用LinkedList实现替换图中的Set个对象,但这需要更改您的一些逻辑。

无论如何,这似乎相关:Best algorithm for detecting cycles in a directed graph