0、什么是环?
在图论中,环(英语:cycle)是一条只有第一个和最后一个顶点重复的非空路径。

在有向图中,一个结点经过两种路线到达另一个结点,未必形成环。

使用拓扑排序可以判断一个无向图中是否存在环,具体步骤如下:
使用拓扑排序判断无向图和有向图中是否存在环的区别在于:
import java.util.LinkedList;
import java.util.Queue;
public class Graph {
    private int numVertices; // 图的顶点数
    private LinkedList<Integer>[] adj; // 邻接表
    public Graph(int numVertices) {
        this.numVertices = numVertices;
        adj = new LinkedList[numVertices];
        for (int i = 0; i < numVertices; i++) {
            adj[i] = new LinkedList<>();
        }
    }
    // 添加边
    public void addEdge(int source, int dest) {
        adj[source].add(dest);
    }
    // 使用拓扑排序检测环
    public boolean isCyclic() {
        int[] inDegree = new int[numVertices];
        for (int i = 0; i < numVertices; i++) {
            for (int node : adj[i]) {
                inDegree[node]++;
            }
        }
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numVertices; i++) {
            if (inDegree[i] == 0) {
                queue.add(i);
            }
        }
        int count = 0;
        while (!queue.isEmpty()) {
            int current = queue.poll();
            for (int node : adj[current]) {
                if (--inDegree[node] == 0) {
                    queue.add(node);
                }
            }
            count++;
        }
        return count != numVertices;
    }
    public static void main(String[] args) {
        Graph graph = new Graph(4);
        graph.addEdge(0, 1);
        graph.addEdge(1, 2);
        graph.addEdge(2, 3);
        graph.addEdge(3, 1);
        System.out.println("The graph has a cycle: " + graph.isCyclic());
    }
}
使用 DFS 可以判断一个无向图和有向中是否存在环。深度优先遍历图,如果在遍历的过程中,发现某个结点有一条边指向已访问过的结点,并且这个已访问过的结点不是上一步访问的结点,则表示存在环。
我们不能仅仅使用一个 bool 数组来表示结点是否访问过。规定每个结点都拥有三种状态,白、灰、黑。开始时所有结点都是白色,当访问过某个结点后,该结点变为灰色,当该结点的所有邻接点都访问完,该节点变为黑色。