要想对一副有向图进行拓扑排序,必须要保证有向图是无环的,那么我们如何判断图是否含有环呢?我们可以使用深度优先搜索来遍历图,并创建一个数组来标记顶点是否已经在递归栈中,这样,当一个顶点指向的顶点已经在递归栈中,说明存在一个环,使用一个数组来记录当前遍历节点的上一个节点,这样就能得到这个环中的所有节点了。
有向环的API
public calss DirectedCycle
DirectedCycle(Digraph G) 寻找有向环的构造函数
boolean hasCycle() 是否存在环
Iterable cycle() 有向环中的所有节点(如果存在)
具体代码实现:
public class DirectedCycle{
private boolean[] marked; //是否已经遍历过
private boolean[] onStack; //是否在递归栈中
private int[] edgeTo; //记录当前节点的前一个节点
private Stack<Integer> cycle; //环中的所有节点
//Digraph类请看前面的一篇有向图的邻接表实现
public DirectedCycle(Digraph G){
marked = new boolean[G.V()];
onStack = new boolean[G.V()];
edgeTo = new int[G.V()];
for(int i=0;i<G.V();i++){
dfs(G,i);
}
}
//深度优先搜索
private void dfs(Digraph G, int v){
onStack[v] = true; //把当前节点加入递归栈
marked[v] = true; //标记当前节点已访问过
for(int w:G.adj(v)){
if(this.hasCycle()) return;
else if(!marked[w]){
edgeTo[w] = v;
dfs(G,w);
}
//如果w已在栈中,说明存在栈
else if(onStack[w]){
cycle = new Stack<Integer>();
for(int i=v;i!=w;i = edgeTo[i]){
cycle.push(i);
}
cycle.push(w);
cycle.push(v);
}
}
onStack[v] = false;
}
//判断是否有环
public boolean hasCycle(){
return cycle!=null;
}
//返回环中的所有节点
public Iterable<Integer> cycle(){
return cycle;
}
}