/*深度优先遍历,从点v递归走到点w,那么w的邻接集里已经被marked的点如果不是只有点v,就有环。
即当前递归里需要上一个被递归的点来做判断,所以加了一个形参。有向图不能用这个
*/
function dfs(v,G){
var marked=[]
//from[v]=v
for(let i=0;i<V;i++){
marked[i]=false
}
dfs_(v,G,marked,v)
}
function dfs_(v,G,marked,prev){
//console.log(v,G,marked,prev)
marked[v]=true
for(let j in G[v]){
let w=G[v][j]
/*if(!passedStart&&w==start){ //用来给start设置from,书上没有这行,注释掉
from[w]=v
passedStart=true
}*/
if(!marked[w]){
from[w]=v
dfs_(w,G,marked,v)
}else if(w!=prev){
hasCycle=true
console.log(getPath(w,v,from))
/*假设数据是{0:[1,2],1:[3,4,5],***},遍历顺序从小到大,在4时发现环,
下面的return可以在dfs_(1,**)的w=4时返回,然后执行dfs_(0,**)的w=2的递归。
所以如果想找到环就退出,可以在dfs_加上hasCycle的判断,为true就退出。 */
//return
}
}
/*算法4上getPath没有s参数,默认是0。这里为了找出全部的环,加了个参数。
但这样会导致经过0处bug,因为from[0]=0或者from[0]=undefined,
或者在dfs使用passedStart给from[0]设置其他点(必定是dfs扫描的第一个点),都会导致死循环。
即使getPath里处理这些情况,还是没找到打印出所有环的方法。
所以注释掉了特殊情况处理,保留了和书上一样的代码。运行时很可能报错。
*/
function getPath(s,v,from){
//console.log('start-->',s,v)
var path=[v]
//var c=0
while(v!=s){
//c++
//if(c%10000==9999)console.log(s,v,from)
v=from[v]
//if(path.indexOf(v)!=-1){
//console.log(s,v,from)
//return
//}
path.unshift(v)
}
path.push(s)
return path
}
let generateGraph=require("./graph").generateGraph
let V=100
var edges=[]
for(let i=0;i<V*2;i++){
let x=Math.floor(Math.random()*V)
let y=Math.floor(Math.random()*V)
edges.push([x,y])
}
//console.log(G=generateGraph(V,edges))
console.log(G=generateGraph(V,edges))
var hasCycle=false //本来想尽量不用全局变量,不过这里用了会方便很多
var from=[]
var passedStart=false
var start=0
dfs(start,G)
//console.log('from-->',from)
console.log(hasCycle)