Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 使用字典数据结构查找有向图中至少有3个节点的所有循环_Python 3.x_Dictionary_Graph_Depth First Search_Directed Graph - Fatal编程技术网

Python 3.x 使用字典数据结构查找有向图中至少有3个节点的所有循环

Python 3.x 使用字典数据结构查找有向图中至少有3个节点的所有循环,python-3.x,dictionary,graph,depth-first-search,directed-graph,Python 3.x,Dictionary,Graph,Depth First Search,Directed Graph,上图是使用乳胶绘制的: 上图用Python表示为一个字典 图形={ 'A':['B','D','C'], “B”:[C'], “C”:[…], “D”:[E'], “E”:[G'], “F”:[A”,“I'], 'G':['A','K'], 'H':['F','G'], “I”:[H'], 'J':['A'], 'K':[] } 我有一个大约3378546个节点的大图 给出上面的有向图,我试图找到至少有3个和少于5个不同节点的圆,并输出前3个圆 我花了一天半的时间解决这个问题。我查看了Stac

上图是使用乳胶绘制的:

上图用Python表示为一个字典

图形={
'A':['B','D','C'],
“B”:[C'],
“C”:[…],
“D”:[E'],
“E”:[G'],
“F”:[A”,“I'],
'G':['A','K'],
'H':['F','G'],
“I”:[H'],
'J':['A'],
'K':[]
}
我有一个大约3378546个节点的大图

给出上面的有向图,我试图找到至少有3个和少于5个不同节点的圆,并输出前3个圆

我花了一天半的时间解决这个问题。我查看了Stackoverflow,甚至尝试按照本教程进行操作,但没有找到解决方案

在本例中,输出是一个以制表符分隔的文本文件,其中每行都有一个循环

0a、D、E、G
1 F,I,H
0
1
是索引。 此外,图形节点的字母表中没有顺序

我尝试了以下表单教程:

visted=set()
def dfs(已访问、图形、节点):
如果未访问节点:
打印(节点)
已访问。添加(节点)
对于图[node]中的邻居:
dfs(访问、图表、邻居)
dfs(已访问,图表“A”)

但这没用。我还尝试了这个

这里有一个注释代码,它将打印包含找到的循环的数组。我认为,将返回值调整为所需格式(我认为在您的情况下是CSV)不需要更多

可能是因为有了3M个节点,这会变得很慢。然后我建议采用动态编程的方式,缓存/记忆一些递归的结果,以避免重复它们

我希望这能解决你的问题,或者至少对你有所帮助

def cycles_rec(root, current_node, graph, depth, visited, min_depth, max_depth):
    depth += 1

    # First part our stop conditions
    if current_node in visited or current_node not in graph.keys():
        return ''

    if depth >= max_depth:
        return ''

    visited.append(current_node)

    if root in graph[current_node] and depth >= min_depth:
        return current_node

    # The recursive part
    # for each connection we try to find recursively one that would cycle back to our root
    for connections in graph[current_node]:
        for connection in connections:
            result = cycles_rec(root, connection, graph, depth, visited, min_depth, max_depth)
            # If a match was found, it would "bubble up" here, we can return it along with the
            # current connection that "found it"
            if result != '':
                return current_node + ' ' + result

    # If we are here we found no cycle        
    return ''

def cycles(graph, min_depth = 3, max_depth = 5):
    cycles = {}
    for node, connections in graph.items():
        for connection in connections:
            visited = []
            # Let the recursion begin here
            result = cycles_rec(node, connection, graph, 1, visited, min_depth, max_depth)
            if result == '':
                continue 
            # Here we found a cycle.
            # Fingerprint is only necessary in order to not repeat the cycles found in the results
            # It could be ignored if repeating them is not important
            # It's based on the fact that nodes are all represented as letters here
            # It could be it's own function returning a hash for example if nodes have a more
            # complex representation
            fingerprint = ''.join(sorted(list(node + ' ' + result)))
            if fingerprint not in cycles.keys():
                cycles[fingerprint] = node + ' ' + result

    return list(cycles.values())
因此,假设您在示例中声明的图形变量:

print(cycles(graph, 3, 5))
会打印出来吗

['A D E G', 'F I H']

注意:此解决方案是所述解决方案的扩展解决方案。我扩展到原始图,有大约300万个节点,我查找所有至少3个节点小于40个节点的循环,并将前3个循环存储到一个文件中


我提出了以下解决方案

Johnson循环查找算法的实现 #原稿:唐纳德·约翰逊。“寻找有向图的所有基本回路”,《暹罗计算杂志》。1975 从集合导入defaultdict 将networkx导入为nx 从networkx.utils导入未实现,成对 @未实施(“未定向”) def findCycles(G): “”“查找有向图的简单圈。 “简单循环”是一个闭合路径,其中没有节点出现两次。 如果两个基本电路不是彼此的循环置换,则它们是不同的。 这是Johnson算法[1]的迭代器/生成器版本。 在某些情况下,可能会有更好的算法[2]\u3]\u3。 参数 ---------- G:NetworkX有向图 有向图 退换商品 ------- 循环发电机:发电机 生成图形基本循环的生成器。 每个循环由沿循环的节点列表表示。 例子 -------- >>>图={'A':['B','D','C'], “B”:[C'], “C”:[…], “D”:[E'], “E”:[G'], “F”:[A”,“I'], 'G':['A','K'], 'H':['F','G'], “I”:[H'], 'J':['A'], 'K':[] } >>>G=nx.DiGraph() >>>G.add_nodes_from(graph.keys()) >>>对于键,graph.items()中的值: G.add_edges_from(([(键,节点)用于值中的节点]) >>>列表(nx.findCycles(G)) [F',I',H',[G',A',D',E']] 笔记 ----- 实施遵循[1]第79-80页。 对于$n$节点、$e$边和$c,时间复杂度为$O((n+e)(c+1))$$ 基本电路。 工具书类 ---------- ..[1]求有向图的所有基本回路。 D.B.Johnson,《暹罗计算机杂志》第4期,第1期,1975年,第77-84页。 https://doi.org/10.1137/0204007 ..[2]枚举有向图的循环:一种新的预处理策略。 G.Loizou和P.Thanish,《信息科学》,第27卷,第163-182页,1982年。 ..[3]有向图的基本圈的搜索策略。 J.L.Szwarcfiter和P.E.Lauer,BIT数值数学, v、 1976年12月16日,第2期,192-204页。 -------- """ def_解除阻止(此节点,已阻止,B): 堆栈={thisnode} 堆栈时: node=stack.pop() 如果节点处于阻止状态: 已阻止。删除(节点) stack.update(B[节点]) B[node].clear() #约翰逊的算法需要对节点进行某种排序。 #我们指定强连通comps给出的任意顺序 #无需跟踪订单,因为每个节点都是在处理过程中删除的。 #我们还保存了实际的图形,以便对其进行变异。我们只坐火车 #边,因为我们不希望在此处复制边和节点属性。 subG=类型(G)(G.边() sccs=[nx中scc的scc。如果列表中的len(scc)(范围(3,41)),则强连接的组件(subG)] #Johnson算法排除自循环边,如(v,v) #为了向后兼容,我们提前记录这些周期 #然后从subG中删除 对于subG中的v: 如果子对象具有_边(v,v): 收益率[v] 子G.移除边缘(v,v) 而SCC: scc=sccs.pop() sccG=子g.子图(scc) #scc的顺序决定了节点的顺序 startnode=scc.pop() #处理节点从递归版本运行“电路”例程 路径=[startnode] blocked=set()#顶点:阻止搜索? closed=set()#循环中涉及的节点 已阻止。添加(startnode)