【问题标题】:Detect cycles in unconnected graph检测未连接图中的循环
【发布时间】:2015-10-05 22:01:37
【问题描述】:

虽然关于这个主题有几个问题,但我需要一些更具体的建议。

我正在做一些我必须重命名实体的项目。这意味着保存一个包含实体旧名称和新名称的新对象。这就是软件的工作原理。

现在,我要做的是检查当有人尝试重命名对象时是否尝试循环依赖。例如:

A -> B
B -> C
C -> A

当有人试图将 C 重命名为 A 时,应该发出信号。

我不确定如何解决这个问题。我的想法是创建一个具有边 [A, B], [B, C], [C, A] 的有向图,并应用一些循环检测算法来找到循环依赖项(Tarjan 或其他东西)。

考虑到图形不会连接,这会有效吗?可以有前面提到的例子,然后:

E -> F
H -> J
X -> Y

我最终会得到很多未连接的边缘和几个循环。我应该先找到较小的连接图并在每个图上应用任何算法,还是有可能只添加构建大图并在其上应用算法?

对于我的示例,检测循环依赖关系的最快和推荐方法是什么?

谢谢!

更新 我想出了以下dfs方法:

void DFS(int root, boolean[] visited){
        onStack = new boolean[N];
        edgeTo = new int[N];

        visited[root]=true;
        onStack[root] = true;

        for (int i=0; i<N; ++i){
            if (G[root][i]){ 
                if(!visited[i]){
                   DFS(i,visited);
                } else if (onStack[i]){
                   System.out.printf("%nCycle %n");
                }
          } else {
              System.out.printf("%nG[" + root + "][" + i + "] is not an edge%n");
          }

          onStack[root] = false;
        }

    }

并这样称呼它:

void DFS()
    {
        boolean[] visited =new boolean[N]; 
        int numComponets=0;

        // do the DFS from each node not already visited
        for (int i=0; i<N; ++i)
            if (!visited[i] && cycle == null)
            {
                ++numComponets;             
                DFS(i,visited);
            } 
    }

它成功地找到了连接的组件,但不识别任何循环,只有当我删除 G[root][i] 条件时,这将是从 0 到 0 的第一个循环。我错过了什么?

【问题讨论】:

    标签: java graph dependencies


    【解决方案1】:

    您可以简单地维护一组所有节点的S。然后你从那个集合中取出一个节点,在那个节点上运行 dfs/bfs,检查后边(如果是这样,你知道你有一个循环)。对于您访问的每个节点,从集合 S 中删除该节点。 dfs/bfs 完成后,检查S 是否为空。如果是这样,那么你知道没有周期。否则,您从S 获取一个节点,并在该节点上运行 dfs/bfs。运行时间应该是 O(n),其中 n 是节点数。

    伪代码:

    S = set(all nodes)
    while len(S) > 0:
        node = S.pop()
        stack = [node]
        visited = set()
        while len(stack) > 0:
            node = stack.pop()
            visited.add(node)
            S.remove(node)
            for each neighbor of node in your graph:
                if neighbor in visited:
                    # you know you have a cycle
    
                else:
                    stack.append(node)
    

    【讨论】:

    • 在这种情况下确实不需要路径搜索算法。 “图”将有一个单向路径,直到有人尝试将实体重命名为以前的名称,在这种情况下,您只需检测该名称/节点是否已被使用。
    • 嗯,不完全是。因为如果我尝试将 C 重命名为 X,即使我已经将 X 存储在列表中,它也应该有效。
    • @user3502249 怎么会不产生循环?
    • 当使用了以前的命名时,循环不一定是闭合的,但是当同一个实体经过一些命名只是返回到它自己的以前的名称时,那就是:
    • A -> B, B ->A A ->B, B -> C, C ->A A ->B, B -> X, X -> Y, Y ->Z, Z -> 一个
    【解决方案2】:

    如果我正确理解了您的问题,那么只有当有人将实体名称更改为该实体以前使用的名称时,您才会得到循环依赖。

    考虑到这一点,为什么不使用实体拥有的所有名称创建一个集合,并且每当用户尝试更改名称时,请检查该名称是否在您的集合中。如果是,那么这将创建一个循环依赖,如果它不在您的集合中,则将其添加到集合中并允许名称更改操作继续。

    HashSet 这样的集合对这种方法很有用,因为它为您提供了平均 O(1) 的元素查找时间复杂度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-05
      • 2013-05-02
      • 1970-01-01
      • 2016-03-28
      相关资源
      最近更新 更多