修改深度优先搜索Python

时间:2017-03-17 10:17:06

标签: python recursion graph-theory depth-first-search

我希望通过图表来查找以特定方式连接的节点。

graphed = {
    1: [25, 30], 2: [11], 3: [13], 4: [17], 5: [17],
    6: [26], 7: [11, 12], 8: [10, 13], 9: [14, 26],
   10: [8, 11, 15], 11: [2, 7, 10], 12: [7, 16, 17],
   13: [3, 8, 14], 14: [9, 13, 20], 15: [10, 19],
   16: [12, 18], 17: [4, 5, 12], 18: [16, 21, 22],
   19: [15, 28, 29], 20: [14, 25], 21: [18, 23],
   22: [18, 24], 23: [21, 27], 24: [22, 27], 25: [1, 20],
   26: [6, 9], 27: [23, 24], 28: [19], 29: [19], 30: [1]
}

letters = {
    'S': [1],
    'C': [10, [11], [12], [13], [14], [15], [16], [17],
              [18], [19], [20], [21], [22], [23], [24],
              [25], [26], [27], [28], [29], [30] ],
    'O': [2, [3], [4], [5], [6]],
    'N': [7, [8], [9]]}


some_string = 'CO'

def dfs(graph, start, num, visited = None):
    # depth first search for connected nodes
    k = some_string[num]
    y = some_string[(num+1)]
    if visited is None:
        visited = []

    if start in visited:
        return

    visited.append(start)
    # if start corresponds to first letter of string, continue
    if start in letters.get(k):
        # find all nodes that it is connected too
        for each in [x for x in graph[start] if x not in visited]:
            # if any of the connected nodes correspond to
            #   the next letter of string, continue...
            if [each] in letters.get(y):
                dfs(graph, each, (num+1), visited) #recursion

    return visited

lst1 = []
for i in range(1,len(graphed)): 
     lst1.append(dfs(graphed, i, 0))
print(lst1)

目前,DFS函数返回的所有内容都是原始起始值,i在范围内。

[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
 [11], [12], [13], [14], [15], [16], [17], [18], [19], [20],
 [21], [22], [23], [24], [25], [26], [27], [28], [29]]

我希望如此:

[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
 [11, 2], [12], [13,3], [14], [15], [16], [17,4], [17,5],
 [18], [19], [20], [21], [22], [23], [24], [25], [26,6],
 [27], [28], [29]]

澄清一下:我希望程序运行dfs函数;如果起始值是'C'中的值,找到所有连接的节点并检查它们是否在'O'中;如果是的话,与他们一起做dfs;如果没有,则返回单个值。

希望这很清楚,我无法理解为什么它不起作用。感谢任何帮助。谢谢。

2 个答案:

答案 0 :(得分:1)

此代码存在一些问题。我建议你重新开始并使用增量编程:编写几行代码,调试它们,并且在它们以你想要的方式工作之前不要继续。你没有得到你的评论似乎假设的一些功能。

  1. 我不确定您访问的节点列表是否按预期运行。每次返回主程序中的 for 循环时,都会重置此项。
  2. 您的主程序没有点击最后一个节点,30。
  3. 我怀疑你的主要问题是你的节点符号。我不确定您打算使用 [7,[8],[9]] 之类的列表,其中节点编号位于不同的嵌套级别,但您的逻辑似乎假设没有筑巢。你找不到一些东西,例如,你在列表 [10,[11],[12],...] 中搜索元素 11 - - 这是 False [11] 是后一个列表的元素,但 11 不是。
  4. 请参阅这个可爱的debug博客以获取帮助。

    我做了一些调试,包括将一些变量名更改为更有意义的名称。这就是我目前所拥有的,严格的低技术印刷声明。

    graphed = {
        1: [25, 30], 2: [11], 3: [13], 4: [17], 5: [17],
        6: [26], 7: [11, 12], 8: [10, 13], 9: [14, 26],
       10: [8, 11, 15], 11: [2, 7, 10], 12: [7, 16, 17],
       13: [3, 8, 14], 14: [9, 13, 20], 15: [10, 19],
       16: [12, 18], 17: [4, 5, 12], 18: [16, 21, 22],
       19: [15, 28, 29], 20: [14, 25], 21: [18, 23],
       22: [18, 24], 23: [21, 27], 24: [22, 27], 25: [1, 20],
       26: [6, 9], 27: [23, 24], 28: [19], 29: [19], 30: [1]
    }
    
    letters = {
        'S': [1],
        'C': [10, [11], [12], [13], [14], [15], [16], [17],
                  [18], [19], [20], [21], [22], [23], [24],
                  [25], [26], [27], [28], [29], [30] ],
        'O': [2, [3], [4], [5], [6]],
        'N': [7, [8], [9]]}
    
    
    node_path = 'CO'
    
    def dfs(graph, start, num, visited = None):
        print("ENTER dfs", start, num, visited)
        # depth first search for connected nodes
        start_ltr = node_path[num]
        end_ltr = node_path[(num+1)]
        if visited is None:
            visited = []
    
        if start in visited:
            return
    
        visited.append(start)
        # if start corresponds to first letter of string, continue
        print("  search for start node", start, "in list", start_ltr, letters.get(start_ltr))
        if start in letters.get(start_ltr):
            # find all nodes that it is connected too
            for each in [x for x in graph[start] if x not in visited]:
                print("    found", each, "in", graph[start]) 
                print("    search in list", end_ltr, letters.get(end_ltr))
                # if any of the connected nodes correspond to
                #   the next letter of string, continue...
                if [each] in letters.get(end_ltr):
                    dfs(graph, each, (num+1), visited) #recursion
    
        print("LEAVE dfs", visited)
        return visited
    
    lst1 = []
    for i in range(1,15):    # I cut back the list for less output.
         lst1.append(dfs(graphed, i, 0))
    print(lst1)
    

    输出:

    $ python3 so.py
    ENTER dfs 1 0 None
      search for start node 1 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [1]
    ENTER dfs 2 0 None
      search for start node 2 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [2]
    ENTER dfs 3 0 None
      search for start node 3 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [3]
    ENTER dfs 4 0 None
      search for start node 4 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [4]
    ENTER dfs 5 0 None
      search for start node 5 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [5]
    ENTER dfs 6 0 None
      search for start node 6 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [6]
    ENTER dfs 7 0 None
      search for start node 7 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [7]
    ENTER dfs 8 0 None
      search for start node 8 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [8]
    ENTER dfs 9 0 None
      search for start node 9 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [9]
    ENTER dfs 10 0 None
      search for start node 10 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
        found 8 in [8, 11, 15]
        search in list O [2, [3], [4], [5], [6]]
        found 11 in [8, 11, 15]
        search in list O [2, [3], [4], [5], [6]]
        found 15 in [8, 11, 15]
        search in list O [2, [3], [4], [5], [6]]
    LEAVE dfs [10]
    ENTER dfs 11 0 None
      search for start node 11 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [11]
    ENTER dfs 12 0 None
      search for start node 12 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [12]
    ENTER dfs 13 0 None
      search for start node 13 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [13]
    ENTER dfs 14 0 None
      search for start node 14 in list C [10, [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]]
    LEAVE dfs [14]
    [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14]]
    

    这会让你感动吗?

答案 1 :(得分:1)

您的letters词典格式不正确。

'C': [10, [11], [12], [13], [14], [15], [16], [17],
          [18], [19], [20], [21], [22], [23], [24],
          [25], [26], [27], [28], [29], [30] ],
'O': [2, [3], [4], [5], [6]],
'N': [7, [8], [9]]}

请注意每个字母的第一个数字是如何直接在顶级列表中,但每个其他条目本身都在子列表中。因此,对于可能连接到O的每个C节点,if start in letters.get(k)将为false。

>>> 10 in letters.get("C")
True
>>> 11 in letters.get("C")
False

所以我把字典改成了这个:

letters = {
    'S': [1],
    'C': [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
    'O': [2, 3, 4, 5, 6],
    'N': [7, 8, 9]}

您必须相应地更改此行:

if [each] in letters.get(y):

if each in letters.get(y):

另外,为了让每次递归调用的结果实际传回,我不得不改变这一行:

dfs(graph, each, (num+1), visited) #recursion  

return dfs(graph, each, (num+1), visited) #recursion

最后,在方法的顶部添加一个特殊情况,以便找到所有some_string时:

def dfs(graph, start, num, visited = None):
    # depth first search for connected nodes
    if (num+1 == len(some_string)):
        return visited + [start]

此时,搜索成功,因此没有更多信件可以搜索!