拓扑排序+判断图中是否有环
拓扑排序:从一个顶点开始,进行dfs,直到某一个点再也没有出度,没有出度的点可以认为是最大的点(之一)。
是否有环:为visited数组多添加一个状态:正在被访问状态。如果在一次递归中两次碰到被标记为-1的点,证明成了环
public class Topo {
//顶点数
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];
//拓扑排序结果
static int [] topo=new int [n];
//标记topo数组的哪一位被改写
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);
//如果dfs返回false,证明有环
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)//大于0证明的当前顶点i到顶点j有出度
{
//此处,关于顶点j的递归还没有退出,前驱的状态是-1,后继的状态也是-1,说明在此递归的链路上早就路过了j,现在是第二次路过j
//一次递归,两次经过同一个顶点,只有一种情况,形成了环
if(vis[j]<0)
return false;
//j没被访问过,执行递归
if(vis[j]==0&&dfs(j)==false)
return false;//有环
}
}
//for循环走完证明递归走到了末端,该顶点的再无未被访问过的邻居,也就是再无出度
//此时应该将该点更新到topo数组中
topo[--t]=i;
vis[i]=1;
return true;
}
}