简体   繁体   English

如何检测字典中的循环?

[英]How to detect a cycle in a dictionary?

I have the following dictionary with the first number being the node, followed by a tuple consisting of a neighbor and then the edge weight (some nodes have multiple neighbors and weights):我有以下字典,第一个数字是节点,后跟一个由邻居组成的元组,然后是边权重(某些节点有多个邻居和权重):

dictionary = {1: [(2, 3), (4, 5), (6, 2)], 2: [(3, -4)], 3: [(8, 4)], 4: [(5, 6)], 5: [(4, -3), (8, 8)], 6: [(7, 3)], 7: [(6, -6), (8, 7)]}

How would I use Depth First Search (DFS) to detect if there is a cycle or not?我将如何使用深度优先搜索 (DFS) 来检测是否存在循环? The dictionary will be changed frequently for testing purposes, so some may have cycles and some may not.出于测试目的,字典会经常更改,因此有些可能有循环,有些可能没有。 I am new to python and do not understand how to implement DFS to check for a cycle or not.我是 python 的新手,不明白如何实施 DFS 来检查周期。 I have the following DFS code:我有以下 DFS 代码:

visited = set() # Set to keep track of visited nodes of graph.

def dfs(visited, dictionary, node):  #function for dfs
    if node not in visited:
        print (node)
        visited.add(node)
        for neighbour in dictionary[node]:
            dfs(visited, dictionary, neighbour)

and then I call the function: dfs(visited, dictionary, '1') .然后我调用 function: dfs(visited, dictionary, '1')

But I get the error KeyError: '1' .但我收到错误KeyError: '1' I also am unsure how to use this code to detect for a cycle or not.我也不确定如何使用此代码来检测周期。

First we consider the base cases.首先,我们考虑基本情况。 In this instance, we wish to evaluate whether the graph has a cycle or not.在这种情况下,我们希望评估图是否具有循环。 The function should return true when a cycle is detected, and false if no such cycle exists after all edges have been examined.当检测到一个循环时,function 应该返回真,如果在检查所有边之后不存在这样的循环,则返回假。

dictionary = {1: [(2, 3)], 2: [], 3: [(4, 4)], 4: [(3, 6)]}

def DFS(visited, dictionary, node):
    if node in visited:
        return True
    else:
        for neighbour, weight in dictionary[node]:
            if DFS(visited | {node}, dictionary, neighbour):
                return True
        return False

print(f"{DFS(set(), dictionary, 1)=}") # False

Depth first search will examine all paths from a single node, going exploring as far as it can before backtracking.深度优先搜索将检查来自单个节点的所有路径,在回溯之前尽可能地探索。 If it encounters a node it has seen before, the search will stop and the function returns true.如果遇到以前见过的节点,搜索将停止,function 返回 true。 If all paths from the starting node have been exhausted, it returns false.如果起始节点的所有路径都已用尽,则返回 false。 This will only detect whether node 1 is involved in any cycles.这只会检测节点 1 是否参与任何循环。

However, this approach is not enough to detect cycles which does not involve the starting node.然而,这种方法不足以检测不涉及起始节点的循环。 In the above example, the DFS will not find the cycle between nodes 3 and 4, as it starts its search from 1.在上面的例子中,DFS 不会找到节点 3 和 4 之间的循环,因为它从 1 开始搜索。

To fix this, we can write another function which examines all the nodes with the DFS.为了解决这个问题,我们可以编写另一个 function 来检查所有具有 DFS 的节点。

def containsCycle(dictionary):
    for node in dictionary.keys():
        if DFS(set(), dictionary, node):
            return True
    return False

print(f"{containsCycle(dictionary)=}") # True
dictionary = {1: [(2, 3), (4, 5), (6, 2)], 2: [(3, -4)], 
              3: [(8, 4)], 4: [(5, 6)], 5: [(4, -3), (8, 8)], 
              6: [(7, 3)], 7: [(6, -6), (8, 7)]}

The dictionary above has a edges to a node 8, without an entry for that node in the dictionary.上面的字典有一条到节点 8 的边,但字典中没有该节点的条目。 This will cause an error.这将导致错误。 To resolve this, we can add a guard clause to our recursive function.为了解决这个问题,我们可以在递归 function 中添加一个保护子句。

def DFS(visited, dictionary, node):
    if node in visited:
        return True
    elif node not in dictionary: # Guard clause
        return False
    else:
        for neighbour, weight in dictionary[node]:
            if DFS(visited | {node}, dictionary, neighbour):
                return True
        return False

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

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