简体   繁体   English

使用迭代方法从 Python 中的起始节点到达图中的目标节点

[英]Reaching a destination node in a graph from a start node in Python using iterative approach

I have the following undirected graph, in which I am trying to reach node 5 destination node starting from node 0 via all the paths available and not just a single or the shortest one.我有以下无向图,其中我试图通过所有可用路径从节点0开始到达节点5目标节点,而不仅仅是单个或最短的路径。

The graph is a dictionary as such:该图是这样的字典:

graph = {   "0" : ["2", "1"],
            "2" : ["0", "3", "4"],
            "3" : ["2"],
            "1" : ["0", "5"],
            "4" : ["2", "5"],
            "5" : ["1", "4"]
        }

在此处输入图像描述

My approach is to start with the start node, then iterate through each neighbor, and then through their neighbors until a destination is reached.我的方法是从起始节点开始,然后遍历每个邻居,然后遍历他们的邻居,直到到达目的地。

However, the issue I am facing is that, I can not change the main iterative in the for loop to a new one real-time (Not possible and highly not recommended).但是,我面临的问题是,我无法将 for 循环中的主要迭代实时更改为新的迭代(不可能,强烈不推荐)。

For example, If I start to loop in the neighbors of 0 which are 2 and 1 , I would be looping through [2, 1] initially, I would then loop between 3 and 4 as they are the neighbors of 2 , however, I can't change this in the for loop as the iterative will still remain [2, 1] instead of becoming [3, 4] .例如,如果我开始在0的邻居中循环,即21 ,我最初会循环通过[2, 1] ,然后我会在34之间循环,因为它们是2的邻居,但是,我无法在 for 循环中更改它,因为迭代仍将保持[2, 1]而不是变为[3, 4] Also, [2, 1] needs to be kept referenced in a way that after node 3 and node 4 and it's neighbors [5] are traversed, the 2nd node in the first iterator 1 should be traversed alongside it's neighbor which is [1] in this case.此外, [2, 1]需要以这样的方式保持引用,即在遍历节点3和节点4及其邻居[5]之后,第一个迭代器1中的第二个节点应该与它的邻居[1]一起遍历在这种情况下。

You can do it iteratively using a stack structure that holds the list of next nodes to explore and the path to reach them.您可以使用包含要探索的下一个节点列表和到达它们的路径的堆栈结构来迭代地执行此操作。

for example:例如:

def findPath(graph, origin,target):
    stack  = [(origin,[origin])] # Start from origin
    seen   = {origin}            # Track where you've been so far
    while stack:
        node, path = stack.pop(0)                  # BFS (use pop(-1) for DFS)
        for nextNode in graph[node]:               # Go through neighbours
            if nextNode in seen: continue          #    not seen yet
            nextPath = path + [nextNode]           # Record path to get there
            if nextNode == target: return nextPath # Arrived!
            seen.add(nextNode)                     # Avoid returning here
            stack.append( (nextNode,nextPath) )    # Stack for more exploration
    return [] # no path to target

output: output:

graph = {   "0" : ["2", "1"],
            "2" : ["0", "3", "4"],
            "3" : ["2"],
            "1" : ["0", "5"],
            "4" : ["2", "5"],
            "5" : ["1", "4"]
        }
print(findPath(graph,"0","5"))
['0', '1', '5']

print(findPath(graph,"3","5"))
['3', '2', '4', '5']

print(findPath(graph,"1","3"))
['1', '0', '2', '3']

BFS (Breadth First Search) will find the shortest path. BFS(广度优先搜索)将找到最短路径。 DFS (Depth First search) will consume less memory but may not find an optimal path. DFS(深度优先搜索)会消耗更少的 memory 但可能找不到最佳路径。

To get all the possible paths, you can convert this function into a generator but then you can't use the 'seen' optimization as it would short circuit multiple partial paths reaching the same node.要获得所有可能的路径,您可以将此 function 转换为生成器,但是您不能使用“已看到”优化,因为它会使到达同一节点的多个部分路径短路。 In this case you should use DFS because you're gonna explore all paths anyway and DFS will be more memory efficient.在这种情况下,您应该使用 DFS,因为无论如何您都将探索所有路径,并且 DFS 的 memory 效率更高。

def findPaths(graph, origin,target):
    stack  = [(origin,[origin])] # Start from origin
    while stack:
        node, path = stack.pop(-1)                 # DFS (use pop(0) for BFS)
        for nextNode in graph[node]:               # Go through neighbours
            if nextNode in path: continue          # don't loop inside paths 
            nextPath = path + [nextNode]           # Record path to get there
            if nextNode == target:
                yield nextPath                     # Return this path, 
                continue                           #   continue with others
            stack.append( (nextNode,nextPath) )    # Stack for more exploration

ouput:输出:

graph = {   "0" : ["2", "1"],
            "2" : ["0", "3", "4"],
            "3" : ["2"],
            "1" : ["0", "5"],
            "4" : ["2", "5"],
            "5" : ["1", "4"]
        }

for path in findPaths(graph,"0","5"): print(path)
['0', '1', '5']
['0', '2', '4', '5']


for path in findPaths(graph,"3","5"): print(path)
['3', '2', '4', '5']
['3', '2', '0', '1', '5']


for path in findPaths(graph,"1","3"): print(path)
['1', '0', '2', '3']
['1', '5', '4', '2', '3']

I'm not sure this answers your question of how to do iteratively but I would suggest you solve it in an recursive approach, therefor different nodes could be run iteratively without interfering with other nodes and could scale infinitely.我不确定这是否回答了您如何迭代地进行操作的问题,但我建议您以递归方式解决它,因此可以迭代地运行不同的节点而不会干扰其他节点并且可以无限扩展。 what I mean is you'll take the loop of neighboring nodes and make it a function that receives destination node and current node and does the logic you've already implemented, for each node that isn't the destination node you would run the function on the node.我的意思是您将采用相邻节点的循环并将其设置为 function 接收目标节点和当前节点并执行您已经实现的逻辑,对于每个不是目标节点的节点,您将运行 function在节点上。 GL总帐

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

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