判断图是否有环
附带Leetcode 课程表的Java解
拓扑排序
无向图
- 求出图中所有顶点的度
- 把图中所有度 <=1 的顶点放入队列Q中
- 依次抛出队列Q中的顶点,将抛出的顶点相关联的顶点的度减1,并判断关联顶点的度是否<=1,如果是,则也放入队列Q。
- 直到Q中无任何顶点时,判断Q中抛出的点的数量是否等同于图中所有顶点的数量,如果等于,则无环;如果不等于,则有环。
Q中抛出的点的顺序即拓扑排序的顺序。
有向图
- 求出图中所有顶点的度
- 把图中所有入度 =0 的顶点放入队列Q中
- 依次抛出队列Q中的顶点,将抛出的顶点出度(因此要维护一个出度的列表)的顶点的入度减1,并判断出度的顶点的入度是否=0,如果是,则也放入队列Q。
- 直到Q中无任何顶点时,判断Q中抛出的点的数量是否等同于图中所有顶点的数量,如果等于,则无环;如果不等于,则有环。
Q中抛出的点的顺序即拓扑排序的顺序。
DFS
有向和无向区别不大,具体在于相邻节点处,有向图可能会构成环,但是无向图不会。
具体步骤如下:
深度优先遍历该图,如果在遍历的过程中,发现某个节点有一条边指向已经访问过的节点,并且这个已访问过的节点不是当前节点的父节点(这里的并且应该只是针对无向图),则表示存在环。
我们不能仅仅使用一个bool数组来标志节点是否访问过。
对每个节点分为三种状态,白、灰、黑。
开始时所有节点都是白色,当开始访问某个节点时该节点变为灰色,当该节点下面的所有节点都被访问完,返回到该节点时,该节点變成黑色。
那么我们的算法则为:如果遍历的过程中发现某个节点有一条边指向颜色为灰的节点,那么存在环。
Leetcode 207 课程表
将每个课程变成顶点就好多啦。这道题就变成了判断一个有向图是否有环了。
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
Map<Integer, Node> map = new HashMap<>();
for(int[] nums : prerequisites){
if(!map.containsKey(nums[0])){
map.put(nums[0], new Node(nums[0]));
}
if(!map.containsKey(nums[1