如果学习x课程前必须先学习y课程,学习y课程前必须先学习z课程,学习z课程前必须先学习x课程,那么一定是有问题了,我们就没有办法学习了,因为这三个条件没有办法同时满足。其中这三门课程x,y,z的条件组成了一个环。
因此,如果我们要使用拓扑排序解决优先级问题,首先得保证图中没有环的存在。
1.1检测有向环的API设计
在API中添加onStack[]布尔数组,索引为图的顶点,当我们深度搜索的时:
1:在如果当前顶点正在搜索,则把对应的onStack数组中的值修改为true,标识进栈;
2:如果当前顶点搜索完毕,则把对应的onStack数组中的值改为false,标识出栈;
3:如果即将要搜索某个顶点,但该顶点已经在栈中,则图中有环;
代码实现
public class DirectedCycle {
//索引代表顶点,值表示当前顶点是否已经被搜索
private boolean[] marked;
//记录图中是否有环
private boolean hasCycle;
//索引代表顶点,使用栈的思想,记录当前顶点有没有已经处于正在搜索的有向路径上
private boolean[] onStack;
//创建一个检测对象,检测图G中是否有环
public DirectedCycle(Digraph G){
//初始化marked数组
this.marked = new boolean[G.V()];
//初始化hasCycle数组
this.hasCycle = false;
//初始化onStack数组
this.onStack = new boolean[G.V()];
//找到图中每一个顶点,让每一个顶点作为入口,调用一次dfs进行搜索
for(int v = 0;v < G.V(); v++){
//判断如果当前顶点还没有被搜索过,则调用dfs进行搜索
if(!marked[v]){
dfs(G,v);
}
}
}
/**
* 基于深度优先搜索,检测图G中是否有环
* @param G
* @param v
*/
private void dfs(Digraph G,int v){
//把顶点v表示为已搜索
marked[v] = true;
//把当前顶点进栈
onStack[v] = true;
//进行深度搜索
for (Integer w : G.adj(v)) {
//判断如果当前顶点w没有被搜索过,则继续递归调用dfs方法完成深度优先搜索
if(!marked[w]){
dfs(G,w);
}
//判断当前顶点w是否已经在栈中,如果已经在栈中,证明当前顶点之前处于正在搜索的状态
if(onStack[w]){
hasCycle = true;
return;
}
}
}
/**
* 判断有向环中是否有环
* @return
*/
public boolean hasCycle(){
return hasCycle;
}
}