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)

以下是使用JavaScript和SVG实现Web前端WorkFlow工作流DAG有向无图的步骤: 1. 首先,需要定义一个包含节点和边的数据结构,可以使用邻接表或邻接矩阵来表示。 2. 接下来,需要使用SVG来绘制节点和边。可以使用SVG的circle元素来绘制节点,使用line元素来绘制边。 3. 在绘制节点和边之前,需要计算每个节点的位置。可以使用拓扑排序算法来计算节点的位置,确保没有环。 4. 绘制节点和边时,可以使用鼠标事件来实现节点的拖拽和边的连线。 5. 最后,可以添加一些交互式功能,例如缩放和平移。 以下是一个简单的JavaScript和SVG实现Web前端WorkFlow工作流DAG有向无图的示例代码: ```javascript // 定义节点和边的数据结构 var nodes = [ { id: 1, name: 'Node 1', x: 100, y: 100 }, { id: 2, name: 'Node 2', x: 200, y: 200 }, { id: 3, name: 'Node 3', x: 300, y: 100 } ]; var edges = [ { source: 1, target: 2 }, { source: 2, target: 3 } ]; // 计算节点的位置 var layout = dagre.layout() .nodeSep(50) .rankSep(50) .run({ nodes: nodes, edges: edges }); // 绘制节点和边 var svg = d3.select('svg'); var g = svg.append('g'); var node = g.selectAll('.node') .data(nodes) .enter() .append('g') .attr('class', 'node') .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; }); node.append('circle') .attr('r', 20) .style('fill', 'white') .style('stroke', 'black') .style('stroke-width', '2px'); node.append('text') .attr('dy', '.35em') .text(function(d) { return d.name; }); var edge = g.selectAll('.edge') .data(edges) .enter() .append('line') .attr('class', 'edge') .attr('x1', function(d) { return layout.nodes[d.source].x; }) .attr('y1', function(d) { return layout.nodes[d.source].y; }) .attr('x2', function(d) { return layout.nodes[d.target].x; }) .attr('y2', function(d) { return layout.nodes[d.target].y; }) .style('stroke', 'black') .style('stroke-width', '2px'); // 添加交互式功能 var zoom = d3.zoom() .on('zoom', function() { g.attr('transform', d3.event.transform); }); svg.call(zoom); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值