我正在尝试用Python实现BFS,我理解算法是如何工作的,但我没有太多的编程经验。我花了好几个小时思考代表一切的最佳方式以及如何尽可能高效。我一直无法弄清楚如何从我的起始节点到目标节点获取路径。
我花了很长时间在谷歌上搜索并查看其他人的算法实现,但我的应用程序略有不同,这让我感到困惑。当人们实施BFS时,他们假设他们有一个给他们的图表(就像维基百科关于BFS的文章一样)。在我的问题中,我有一个初始状态和一个我想要达到的目标状态,但没有图形或树,所以我正在生成节点。
例如:
def BFS(initial, goal):
q = [initial]
visited = []
while q:
n = q.pop()
states = generate_states(n)
for state in states:
if state == goal:
pass #placeholder
q.append(state)
visited.append(state)
它没有得到充分的充实,因为我遇到了麻烦,我不确定具体是什么......如果初始和目标是节点,我在我的代码中的其他地方写一个结构类型类,如:
class node:
state = None
parent = None
我认为这是表示节点的合适方式。因此,当我从队列中弹出一个节点对象时,它会有关于它的起源位置的信息,这些信息将由generate_states函数初始化。然后for循环将这些新节点中的每一个附加到队列上,并且访问队列并且它将在其中一个生成的节点下重复,其状态与我的目标状态相匹配。
现在我找到了目标节点,我有一个被访问节点的列表,但是如果我从目标节点向后追踪路径,那么我是不是放慢了算法的速度?一旦找到目标,我会查看其父级,在访问列表中找到其父级,然后查看父级的父级等等......直到我有一个路径= [节点对象,节点对象,... ]从初始节点到目标节点。
这让我想到另一个问题,当我创建一个节点对象时,它只持续while循环的一次迭代。我是如何将对象存储在一个数组中的,它们每个都需要一个唯一的名称,并且没有明显的方法(对我来说)这样做。这是我之前提到的我不确定的问题。所以看起来我正在创建节点,但之后只将node.state存储在队列中,这是没有意义的,因为我要求节点对象访问node.parent ......
为什么我发现这么困难,我是否遗漏了一些显而易见的事情或使其过于复杂?
感谢阅读。
答案 0 :(得分:1)
我不能对大部分内容发表评论,因为我不完全明白你要做的事情 - 正如你所说,通常BFS会在那里有图表,所以我不确定你是怎么做的建议你随时去建造它。但我必须回答这个问题:
我是如何将对象存储在数组中的,它们每个都需要一个唯一的名称
这绝对是假的。如果您只想将其存储在列表中,则无需提供名称 - 您只需将其附加即可。如果你担心以后能够找到它,那么通常用图表做的就是给每个节点一个数字,通过你每次定义时增加的一个计数器。同样,如果您只是将节点存储在列表中,那么它们会自动获得一个唯一的数字:它们在列表中的位置。
答案 1 :(得分:0)
你的方法对我来说很好。
要获取发现路径,您可以跟踪每个节点的父节点,例如给它一个属性,设置为发现它的节点。这样,您就有了一个跟踪发现路径的链表。一旦你到达目标就可以回来了
def get_parents(node):
if node.parent is None:
return []
yield node.parent
get_parents(node)
为了跟踪生成的节点(变量n),只需将发现的节点放入列表中,而不仅仅是状态。
n = q.pop()
states = generate_states(n)
for state in states:
m = node()
m.state = state
m.parent = n
if state == goal:
pass #placeholder
q.append(m)
visited.append(m)
答案 2 :(得分:0)
一般来说,你所拥有的一切都很好。
有几个混淆,我将尝试解释。首先,您可以将节点存储在队列中,而不是状态,并且由于节点具有父节点,因此您可以访问先前的节点,因此您没有丢失它们。其次,通过父母追溯并不是你需要担心效率的问题 - 你只有在你取得成功时才这样做(也就是说,不需要名字 - 听起来像是在混淆列表和地图吗?)。
因此,代码中唯一缺少的是您没有创建节点。获得状态时,创建节点并保存节点,而不是保存状态。一切都会奏效。