图的dfs_拓扑排序(可以检测出图中是否有环)
参考代码:
public class Main {
//顶点数
static final int n = 4;
static String[] v = {"a", "b", "c", "d"};
static int[][] graph = {
{0, 1, 0, 0},
{0, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0}
};
//标记访问状态, 1:已经访问并返回, 0:从未被访问, -1:正在递归访问但还未退出
static int[] vis = new int[n];
//拓扑排序结果(存的是数组v中字符的下标)
static int[] topo = new int[n];
static int t = n;
public static void main(String[] args) {
for (int i = 0; i < n; ++i) {
if (vis[i] == 1) {
continue;
}
//是否有拓扑排序(有环图无拓扑排序)
boolean bool = dfs(i);
if (!bool) {
System.out.println(false);
return;
}
}
for (int i = 0; i < n; ++i) {
System.out.println(v[topo[i]]);
}
}
private static boolean dfs(int i) {
vis[i] = -1;
//遍历所有顶点
for (int j = 0; j < n; ++j) {
if (graph[i][j] > 0) {//当前关注的顶点i到顶点j有出度
//此处,关于j顶点的递归还没有退出,前驱的状态是-1,后继的状态是-1,
// 说明在此次递归的链路上早就路过了j,现在是第二次路过j,
//一次递归中链路两次经过j,只有一种情况,那就是出现了环
if (vis[j] < 0) {
return false;
}
if (vis[j] == 0 && dfs(j) == false) {//dfs(j)==false说明出现了环
return false;
}
}
}
//整个递归是按照出度方向来的,所以上面的循环+递归走到尽头时,i没有出度,
// 没有出度的点可以认为是最大的点(之一)
topo[--t] = i;
vis[i] = 1;
return true;
}
}