简体   繁体   English

检测未连接图中的周期

[英]Detect cycles in unconnected graph

Although there are a few questions on this topic, i would need some piece of advice in a more specific matter. 虽然关于这个主题有几个问题,但我需要一些更具体的建议。

I am working on some project where i have to rename an entity. 我正在做一些我必须重命名实体的项目。 This implies saving a new object containing the old and the new name of the entity. 这意味着保存一个包含实体的旧名称和新名称的新对象。 This is how the soft works. 这是软件的工作原理。

Now, what i have to do is check if a circular dependency is attempted when someone tries to rename an object. 现在,我要做的是检查当有人试图重命名对象时是否尝试循环依赖。 For example: 例如:

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

When someone tries to rename C into A, this should be signaled. 当有人试图将C重命名为A时,应该发出信号。

I am not sure how to approach this problem. 我不知道如何解决这个问题。 My thought was to create a directed graph having the edges[A, B], [B, C], [C, A] and the apply some cycle detecting algorithms to find the circular dependencies (Tarjan or something). 我的想法是创建一个具有边[A,B],[B,C],[C,A]的有向图,并应用一些循环检测算法来找到循环依赖(Tarjan或其他)。

Would that be efficient considering that the graph will not be connected? 考虑到图表不会连接,这会有效吗? It is possible to have the aforementioned example and then: 可以使用上述示例,然后:

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

I will end up with a lot of unconnected edges and a few cycles maybe. 我最终会有很多未连接的边缘,也许会有几个周期。 Should i first find the smaller, connected graphs and apply whatever algorithm on each or is there a possibility to just add build the big one and apply the algorithm on it? 我应该首先找到较小的连接图并在每个图上应用任何算法,或者是否有可能只添加构建大图并在其上应用算法?

What is the fastest and recommended way to detect the circular dependencies for my example? 检测我的示例的循环依赖关系的最快和推荐的方法是什么?

Thank you! 谢谢!

Update I have come up with the following dfs approach: 更新我提出了以下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;
        }

    }

and calling it like this: 并称之为:

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);
            } 
    }

And it successfully finds the connected components, but does not recognize any cycle, only if i remove the G[root][i] condition, that would be the first cycle from 0 to 0. What am i missing? 并且它成功找到连接的组件,但不识别任何循环,只有当我删除G [root] [i]条件时,这将是从0到0的第一个循环。我缺少什么?

If I understood your problem correctly, you'll only get a circular dependency when someone changes the name of the entity to a name previously used by that entity. 如果我正确理解了您的问题,那么当有人将实体名称更改为该实体以前使用的名称时,您将只获得循环依赖关系。

Taking this into account why not just make a collection with all the names the entity had and whenever a user tries to change the name check if the name is in your collection or not. 考虑到这一点,为什么不只是创建一个包含实体所有名称的集合,以及每当用户尝试更改名称时,检查名称是否在您的集合中。 If it is, then this will create a circular dependency, if it's not in your collection then add it to the collection and allow the name changing operation to continue. 如果是,那么这将创建循环依赖项,如果它不在您的集合中,则将其添加到集合并允许名称更改操作继续。

A collection like HashSet would be useful for this approach since it gives you an average O(1) time complexity for element lookup. HashSet这样的集合对于这种方法很有用,因为它为元素查找提供了平均O(1)时间复杂度。

You can simply maintain a set S of all nodes. 您可以简单地维护所有节点的集合S Then you take a node from that set, run dfs/bfs on that node, checking for back edges (if so, you know you have a cycle). 然后从该集合中获取一个节点,在该节点上运行dfs / bfs,检查后沿(如果是,则表示您有一个循环)。 For each node you visit, remove that node from the set S . 对于您访问的每个节点,从集合S删除该节点。 After dfs/bfs is finished, you check if S is empty. 完成dfs / bfs后,检查S是否为空。 If so, then you know there are no cycles. 如果是这样,那么你就知道没有周期。 Otherwise, you take a node from S , and run dfs/bfs on that node. 否则,从S获取一个节点,并在该节点上运行dfs / bfs。 The runtime should be O(n), where n is the number of nodes. 运行时应为O(n),其中n是节点数。

Pseudocode: 伪代码:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM