python中的广度优先搜索陷入无限循环

python中的广度优先搜索陷入无限循环,python,debugging,search,infinite-loop,breadth-first-search,Python,Debugging,Search,Infinite Loop,Breadth First Search,我试图在python中实现广度优先搜索。我试图找到一条穿过网格的路径,从一个正方形开始,找到一条通向目标正方形的路径。整个网格中都有障碍物,标记为“o”。“图形”是指一个二维节点数组,一个简单的类: # Node class class Node: def __init__(self, val, pos): self.val = val self.pos = pos self.visited = False def __str__(

我试图在python中实现广度优先搜索。我试图找到一条穿过网格的路径,从一个正方形开始,找到一条通向目标正方形的路径。整个网格中都有障碍物,标记为“o”。“图形”是指一个二维节点数组,一个简单的类:

# Node class
class Node:
    def __init__(self, val, pos):
        self.val = val
        self.pos = pos
        self.visited = False
    def __str__(self):
        return "%s" % self.val
我意识到这不是BFS最干净的实现——我没有太多使用python的经验,所以有时我不得不使用重复代码,因为我不确定python如何处理某些局部变量下的指针。无论如何,这个BFS循环无限,我不明白为什么。任何帮助都将不胜感激

边缘基本上是一个队列,在更深一层移动之前,将按左、上、右和下的顺序检查每个节点的相邻正方形

# Breadth First Search
def bfs(arena, start):
    # fringe implemented as a FIFO list (behaves like a queue)
    fringe = []
    fringe.append([start])
    start.visited = True
    while fringe:
        # get the first path from the fringe queue
        path = fringe.pop(0)
        print "pop!"
        # get the last node from the path
        node = path[-1]
        # goal check
        if node.val == 'g':
            print "PATH FOUND!!"
            return path
        # get all adjacent nodes, construct a new path and push it to the fringe queue
        pos = node.pos
        # get left node first 
        if pos[1]-1>=0:
            neighbor = graph[pos[0]][pos[1]-1]
            newPath = path[:]
            if neighbor.val == 'o':
                neighbor.visited = True
                graph[pos[0]][pos[1]-1].visited = True
            if neighbor is not neighbor.visited: 
                neighbor.visited = True 
                graph[pos[0]][pos[1]-1].visited = True
                newPath.append(neighbor)
                fringe.append(newPath)
                print "left node added!"
        # get node above current node
        if pos[0]-1>=0:
            neighbor = graph[pos[0]-1][pos[1]]
            newPath = path[:]
            if neighbor.val == 'o':
                neighbor.visited = True
                graph[pos[0-1]][pos[1]].visited = True
            if neighbor is not neighbor.visited:
                neighbor.visited = True
                graph[pos[0-1]][pos[1]].visited = True
                newPath.append(neighbor)
                fringe.append(newPath)
                print "top noded added!"
        # get node to the right of current node
        if pos[1]+1 < columns:
            neighbor = graph[pos[0]][pos[1]+1]
            newPath = path[:]
            if neighbor.val == 'o':
                neighbor.visited = True
                graph[pos[0]][pos[1]+1].visited = True
            if neighbor is not neighbor.visited:
                neighbor.visited = True
                graph[pos[0]][pos[1]+1].visited = True
                newPath.append(neighbor)
                fringe.append(newPath)
                print "right node added!"
        # get node below current node
        if pos[0]+1 < rows:
            neighbor = graph[pos[0]+1][pos[1]]
            newPath = path[:]
            if neighbor.val == 'o':
                neighbor.visited = True
                graph[pos[0]+1][pos[1]].visited = True
            if neighbor is not neighbor.visited:
                neighbor.visited = True
                graph[pos[0]+1][pos[1]].visited = True
                newPath.append(neighbor)
                fringe.append(newPath)
                print "node below added!"
#广度优先搜索
def bfs(竞技场,开始):
#实现为FIFO列表(行为类似于队列)
条纹=[]
附加([开始])
start.visted=True
虽然边缘:
#从边缘队列中获取第一条路径
路径=条纹.pop(0)
打印“pop!”
#从路径中获取最后一个节点
节点=路径[-1]
#进球检查
如果node.val='g':
打印“找到路径!!”
返回路径
#获取所有相邻节点,构建新路径并将其推送到边缘队列
pos=node.pos
#先得到左节点
如果位置[1]-1>=0:
邻居=图形[pos[0][pos[1]-1]
newPath=path[:]
如果neighbor.val='o':
neighbor.visted=True
图[pos[0]][pos[1]-1]。已访问=真
如果邻居不是邻居。已访问:
neighbor.visted=True
图[pos[0]][pos[1]-1]。已访问=真
追加(邻居)
附加(新路径)
打印“已添加左节点!”
#获取当前节点上方的节点
如果位置[0]-1>=0:
邻居=图形[pos[0]-1][pos[1]]
newPath=path[:]
如果neighbor.val='o':
neighbor.visted=True
图[pos[0-1]][pos[1]]。已访问=真
如果邻居不是邻居。已访问:
neighbor.visted=True
图[pos[0-1]][pos[1]]。已访问=真
追加(邻居)
附加(新路径)
打印“已添加顶部节点!”
#获取当前节点右侧的节点
如果位置[1]+1<列:
邻居=图形[pos[0][pos[1]+1]
newPath=path[:]
如果neighbor.val='o':
neighbor.visted=True
图形[pos[0]][pos[1]+1]。已访问=真
如果邻居不是邻居。已访问:
neighbor.visted=True
图形[pos[0]][pos[1]+1]。已访问=真
追加(邻居)
附加(新路径)
打印“添加了右节点!”
#获取当前节点下的节点
如果位置[0]+1<行:
邻居=图形[pos[0]+1][pos[1]]
newPath=path[:]
如果neighbor.val='o':
neighbor.visted=True
图[pos[0]+1][pos[1]]。已访问=真
如果邻居不是邻居。已访问:
neighbor.visted=True
图[pos[0]+1][pos[1]]。已访问=真
追加(邻居)
附加(新路径)
打印“添加下面的节点!”

这是工作代码,请仔细阅读注释

from pprint import pprint

# pos is (row, column), not (x, y)
class Node:
    def __init__(self, val, pos):
        self.val = val
        # Position info is stored here and ALSO as index in graph -
        # this is a form of data duplication, which is evil!
        self.pos = pos
        self.visited = False
    def __repr__(self):
        # nice repr for pprint
        return repr(self.pos)

# You had mistake here, "arena" instead of "graph"
# Before posting questions on stackoverflow, make sure your examples
# at least produce some incorrect result, not just crash.
# Don't make people fix syntax errors for you!
def bfs(graph, start):
    fringe = [[start]]
    # Special case: start == goal
    if start.val == 'g':
        return [start]
    start.visited = True
    # Calculate width and height dynamically. We assume that "graph" is dense.
    width = len(graph[0])
    height = len(graph)
    # List of possible moves: up, down, left, right.
    # You can even add chess horse move here!
    moves = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    while fringe:
        # Print fringe at each step
        pprint(fringe)
        print('')
        # Get first path from fringe and extend it by possible moves.
        path = fringe.pop(0)
        node = path[-1]
        pos = node.pos
        # Using moves list (without all those if's with +1, -1 etc.) has huge benefit:
        # moving logic is not duplicated. It will save you from many silly errors.
        # The example of such silly error in your code:
        # graph[pos[0-1]][pos[1]].visited = True
        #           ^^^
        # Also, having one piece of code instead of four copypasted pieces
        # will make algorithm much easier to change (e.g. if you want to move diagonally).
        for move in moves:
            # Check out of bounds. Note that it's the ONLY place where we check it. Simple and reliable!
            if not (0 <= pos[0] + move[0] < height and 0 <= pos[1] + move[1] < width):
                continue
            neighbor = graph[pos[0] + move[0]][pos[1] + move[1]]
            if neighbor.val == 'g':
                return path + [neighbor]
            elif neighbor.val == 'o' and not neighbor.visited:
                # In your original code there was a line:
                # if neighbor is not neighbor.visited:
                # which was completely wrong. Read about "is" operator.
                neighbor.visited = True
                fringe.append(path + [neighbor])  # creates copy of list
    raise Exception('Path not found!')

if __name__ == '__main__':
    # Graph in convenient form: 0 is empty, 1 is wall, 2 is goal.
    # Note that you can have multiple goals.
    graph = [
        [0, 1, 0, 1],
        [0, 0, 0, 0],
        [0, 1, 0, 1],
        [0, 0, 2, 1]
    ]
    # Transform int matrix to Node matrix.
    TRANSLATE = {0: 'o', 1: 'x', 2: 'g'}
    graph = [[Node(TRANSLATE[x], (i, j)) for j, x in enumerate(row)] for i, row in enumerate(graph)]
    # Find path
    try:
        path = bfs(graph, graph[0][0])
        print("Path found: {!r}".format(path))
    except Exception as ex:
        # Learn to use exceptions. In your original code, "no path" situation
        # is not handled at all!
        print(ex)
从pprint导入pprint
#位置是(行,列),而不是(x,y)
类节点:
定义初始(自我、价值、位置):
self.val=val
#位置信息存储在这里,也作为图中的索引-
#这是一种数据复制形式,这是邪恶的!
self.pos=pos
自我访问=错误
定义报告(自我):
#很好的pprint报告
退货报告(自助销售点)
#你错了,这里是“竞技场”而不是“图形”
#在向stackoverflow发布问题之前,请确认您的示例
#至少会产生一些不正确的结果,而不仅仅是崩溃。
#不要让别人帮你修复语法错误!
def bfs(图表,开始):
条纹=[[start]]
#特殊情况:开始=目标
如果start.val='g':
返回[开始]
start.visted=True
#动态计算宽度和高度。我们假设“图”是稠密的。
宽度=长度(图[0])
高度=长度(图表)
#可能的移动列表:上、下、左、右。
#您甚至可以在此添加棋马移动!
移动=[(-1,0),(1,0),(0,-1),(0,1)]
虽然边缘:
#每一步打印条纹
警察公共关系科(边缘)
打印(“”)
#从边缘获得第一条路径,并通过可能的移动将其延伸。
路径=条纹.pop(0)
节点=路径[-1]
pos=node.pos
#使用移动列表(没有所有带+1、-1等的if)有巨大的好处:
#移动逻辑不重复。它将使你免于犯许多愚蠢的错误。
#代码中此类愚蠢错误的示例如下:
#图[pos[0-1]][pos[1]]。已访问=真
#           ^^^
#而且,有一段代码而不是四段复制粘贴的代码
#将使算法更易于更改(例如,如果您想沿对角线移动)。
对于移入移动:
#退场。请注意,这是我们检查它的唯一地方。简单可依赖!

如果不是(0),您可能想看看这个,您的节点类有一些类变量,将它们放在init中,这可能是您的问题的原因谢谢您指出!我不知道python中的类是如何工作的。我已经更新了它,但问题仍然存在。我将继续查找!
marge.append([start])
应该是
边缘。追加(开始)
。我就是这样开始的,但不应该