业务场景
调度系统的任务可视化界面需要完成用户可在界面上连线作为任意两个job间的依赖关系,也就是DAG图
DAG也就是有向无环图,有向无环图指的是一个无回路的有向图。环是一条至少含有一条边且起点和终点相同的路径。
问题描述
在添加依赖关系时,在向后端发送请求前,前端应该先判断当前添加的连线是否与已存在的依赖关系成为闭环(循环依赖为无效的任务流),减少无效的请求。
job可以任意依赖,也就是每个job可以有多个字节点或者父节点。
环的理解
刚开始以为肉眼能看到的回路就是环,如下图中最终汇合到王小虎4这个节点,但是从有向图的依赖关系来说,实际是1依赖4,1依赖2,2依赖3,3依赖4,只是在等待节点4的执行,并没有陷入死循环的依赖。但是下面这个如果是一个无向图那么就是有环。
有向图和无向图:从图上来说可以简单理解有箭头指向的就是有环图,无箭头指向的为无环图
判断有向图是否有环
有两种算法:
1.深度优先遍历该图,如果在遍历的过程中,发现某个节点有一条边指向已经访问过的节点,则判断为有环。
//图的深度遍历函数
function DFS(i) {
console.log('正在访问结点' + nodes[i]);
//结点i变为访问过的状态
visited[nodes[i]] = 1;
for (let j = 0; j < nodes.length; j++) {
//如果当前结点有指向的结点
if (graph[nodes[i]][nodes[j]] != 0) {
//并且已经被访问过
if (visited[nodes[j]] == 1) {
isDAG = false; //有环
break;
} else if (visited[nodes[j]] == -1) {
//当前结点后边的结点都被访问过,直接跳至下一个结点
continue;
} else {
DFS(j); //否则递归访问
}
}
}
//遍历过所有相连的结点后,把本节点标记为-1
visited[nodes[i]] = -1;
}
//创建图,以邻接矩阵表示
function create(nodes, edges) {
for (let i = 0; i <