python中的广度优先搜索陷入无限循环
我试图在python中实现广度优先搜索。我试图找到一条穿过网格的路径,从一个正方形开始,找到一条通向目标正方形的路径。整个网格中都有障碍物,标记为“o”。“图形”是指一个二维节点数组,一个简单的类: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__(
# 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])
应该是边缘。追加(开始)
。我就是这样开始的,但不应该