js版本判断无向图是否有环并找出环


/*深度优先遍历,从点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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值