图的建立
邻接表
1 | vector<vector<int>> build_tree_with_table(int node_count,vector<vector<int>> prerequisites) |
邻接矩阵
1 | vector<vector<int>> build_tree_with_martix(int node_count,vector<vector<int>> prerequisites) |
图的遍历(获取所有路径)
DFS
使用on_path
判断当前访问的结点是否在当前访问列表中,如果在则表示有环
1 | vector<vector<int>> path_lists; |
判断图是否有环
DFS
使用图的遍历DFS算法,if (on_path[start] == true)
时给has_circle
赋True
另外,使用了is_visited_list。假设现在以节点 2
为起点遍历所有可达的路径,最终发现没有环。
假设另一个节点 5
有一条指向 2
的边,你在以 5
为起点遍历所有可达的路径时,肯定还会走到 2
,此时是否还需要继续遍历 2
的所有可达路径呢?答案是不需要了,因为第一次没找到环,那么这次也不可能找到环
所以,如果发现一个节点之前被遍历过,就可以直接跳过,不用再重复遍历了
1 | bool has_circle; |
BFS
使用拓扑排序,遍历序列即为拓扑排序序列。如果完成遍历后还有结点没有被遍历则存在环
1 | bool canFinish(int numCourses, vector<vector<int>>& prerequisites) { |
拓扑排序
DFS
拓扑排序序列为DFS后序遍历序列取倒置。可以这样理解,后序遍历为左->右->根。遍历完左右子树之后才会执行后序遍历位置的代码。换句话说,当左右子树的节点都被装到结果列表里面了,根节点才会被装进去。
后序遍历的这一特点很重要,之所以拓扑排序的基础是后序遍历,是因为一个任务必须等到它依赖的所有任务都完成之后才能开始开始执行。
倒置后即为拓扑排序序列,使用reverse(path.begin(),path.end())
函数实现
由于为图的后序遍历,所以在邻居结点都被访问后才把当前结点加入遍历序列。这里的is_visited_list
防止结点被重复访问
1 | bool has_circle; |
BFS
同判断图是否有环的BFS实现,修改下返回值为path
遍历序列即可