当前位置: 首页 > 知识库问答 >
问题:

检测有向无环图中的循环引用

景育
2023-03-14

目前我正在用这个样本进行拓扑排序,并对https://www.geeksforgeeks.org/topological-sorting/做了一些修改

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Stack;

public class CalcGraph {

    private int V; // No. of vertices

    private LinkedList<Integer> adj[]; // Adjacency List

    private ArrayList<Integer> result;

    // Constructor
    public CalcGraph(int v) {
        V = v;
        result = new ArrayList<>();
        adj = new LinkedList[v];
        for (int i = 0; i < v; ++i)
            adj[i] = new LinkedList();
    }

    public ArrayList<Integer> getResult() {
        return result;
    }

    public void setResult(ArrayList<Integer> result) {
        this.result = result;
    }

    // Function to add an edge into the graph
    public void addEdge(int v, int w) {
        adj[v].add(w);
    }

    // A recursive function used by topologicalSort
    public void topologicalSortUtil(int v, boolean visited[], Stack<Integer> stack) {
        // Mark the current node as visited.
        visited[v] = true;
        Integer i;

        // Recur for all the vertices adjacent to this
        // vertex
        Iterator<Integer> it = adj[v].iterator();
        while (it.hasNext()) {
            i = it.next();
            if (!visited[i])
                topologicalSortUtil(i, visited, stack);
        }

        // Push current vertex to stack which stores result
        stack.push(new Integer(v));
    }

    public void topologicalSort() {
        Stack<Integer> stack = new Stack<Integer>();

        // Mark all the vertices as not visited
        boolean visited[] = new boolean[V];
        for (int i = 0; i < V; i++)
            visited[i] = false;

        // Call the recursive helper function to store
        // Topological Sort starting from all vertices
        // one by one
        for (int i = 0; i < V; i++)
            if (visited[i] == false)
                topologicalSortUtil(i, visited, stack);

        // Print contents of stack
        while (stack.empty() == false) {
            int graphId = stack.pop();
            result.add(graphId);
        }
    }
}

我用它来排序要求解的变量的顺序。

样本

a = b + c
b = c + d
c = 7
d = c + 1

每个变量都有一个唯一整数,并存储在一个映射中

{
    "1" : { "id" : "a", "child": [b, c]},
    "2" : { "id" : "b", "child": [c, d]},
    "3" : { "id" : "c", "child": []},
    "4" : { "id" : "d", "child": [c]}
}

创建图形并添加边时,总共有4个顶点,因此我的代码将像这样构造图形

CalcGraph g = new CalcGraph(6);
g.addEdge(1, 2);
g.addEdge(1, 3);
g.addEdge(2, 3);
g.addEdge(2, 4);
g.addEdge(4, 3);

排序并按相反顺序得到结果后,它是正确的c

一切都很好,但我需要检测图中的循环引用。假设变量是

a = b + c + d
b = c + d
c = 7
d = c + e
e = a + 1

有一个循环引用,其中“e”需要“a”来完成,但“a”需要“b”、“c”、“d”和“e”先完成。

我不知道如何使用有向无环图检查循环引用。

还是使用不同的数据结构来检查循环引用更好?即树

谢谢

共有1个答案

辛健
2023-03-14

您可以使用int state[]数组来代替布尔值visited[]数组,其中0表示“尚未访问”,“1表示正在进行中”,2表示“完成”。然后,当当前节点依赖于一个“正在进行”的节点时,您就知道您已经找到了一个周期。

我更喜欢使用Kahn的算法进行拓扑排序,它使用更少的堆栈空间并自动检测周期(它会将少于所有节点添加到结果中)。

卡恩的算法是这样的:

public void topologicalSort() {
    result.clear();

    // calculate in-degrees

    int in_degree = new int[V]; //initialized to zeros
    for (int i = 0; i < V; ++i) {
        for(Integer target: adj[i]) {
          ++in_degree[target];
        }
    }

    // add start nodes to result

    for (int i = 0; i < V; ++i) {
        if (in_degree[i]==0) {
            result.add(i);
        }
    }

    // uncount edges from added nodes to find new nodes to add

    for (int scanpos=0; scanpos < result.size(); ++scanpos) {
        for(Integer target: adj[result.get(scanpos)]) {
            if (--in_degree[target] == 0) {
                result.add(target);
            }
        }
    }
    
    //done
    if (result.size() < V) {
        throw new RuntimeException("Ack! a cycle!");
    }
}
 类似资料:
  • 我在这里读到一篇关于在有向图中求圈的讨论。现在,OP声称我们需要验证两件事: 从到有一个后沿 在递归堆栈中 为什么我们需要第二次测试?你能举个例子来说明它的必要性吗?

  • 我有一个带边的无向图。每条边都具有一定的性质,如A点和B点之间的边之一是 在C点和D点之间的另一个可以是 我们得到了这样一个图和已知的旅行路径 有快一点的吗?

  • 因此,我为DFS编写了以下代码: 现在,我读到,在一个无向图中,如果当DFS时,它再次返回到同一个顶点,有一个循环。所以我做的是这样,, 但是,我的检查周期函数返回true,即使他们没有周期。那是为什么呢?我的功能有问题吗?没有执行问题,否则我早就调试了,但他们似乎在我的逻辑中有问题。

  • 问题内容: 我有下表: 存储在其中的实体是按层次结构组织的:如果存在一行,则认为该行是任何内容的“子项” 。由于项目不能从其自身衍生而来,因此我想将存在循环层次序列的行为定为非法: 我该怎么做呢? 另外,我可以在表中添加一个表示层次结构中“级别”的字段: 然后,我要求将其设置为when ,否则。 我正在使用SQL Server 2008 R2。 问题答案: 为了检查循环引用,我使用了触发器和递归C

  • 我有一个简单的类,如下所示: 但我收到以下错误消息: 检测到服务“App\Algorithm\Calculator”的循环引用,路径:“App\Algorithm\Calculator”- MatchService.php 问题是,但我到底做错了什么?