Why is the first path breadth-first search finds always the one with the fewest hops, and why does that promise break with weights?
Short drills on what this video just taught. Write the code, run the checks, and reveal the answer only if you are stuck.
Breadth-first search keeps a queue of paths. One turn of its loop removes the oldest path from the front of pathQueue, then adds to the back one new path for each child of that path's last node that is not already on it. Define bfsStep(graph, pathQueue) that does one such turn (changing pathQueue in place) and returns the path it removed. Skip the goal test.
class Node(object):
def __init__(self, name):
"""Assumes name is a string"""
self.name = name
def getName(self):
return self.name
def __str__(self):
return self.name
class Edge(object):
def __init__(self, src, dest):
"""Assumes src and dest are nodes"""
self.src = src
self.dest = dest
def getSource(self):
return self.src
def getDestination(self):
return self.dest
def __str__(self):
return self.src.getName() + '->' + self.dest.getName()
class Digraph(object):
"""edges is a dict mapping each node to a list of its children"""
def __init__(self):
self.edges = {}
def addNode(self, node):
if node in self.edges:
raise ValueError('Duplicate node')
else:
self.edges[node] = []
def addEdge(self, edge):
src = edge.getSource()
dest = edge.getDestination()
if not (src in self.edges and dest in self.edges):
raise ValueError('Node not in graph')
self.edges[src].append(dest)
def childrenOf(self, node):
return self.edges[node]
def hasNode(self, node):
return node in self.edges
def getNode(self, name):
for n in self.edges:
if n.getName() == name:
return n
raise NameError(name)
def __str__(self):
result = ''
for src in self.edges:
for dest in self.edges[src]:
result = result + src.getName() + '->' + dest.getName() + '\n'
return result[:-1]
class Graph(Digraph):
def addEdge(self, edge):
Digraph.addEdge(self, edge)
rev = Edge(edge.getDestination(), edge.getSource())
Digraph.addEdge(self, rev)
def buildCityGraph(graphType):
g = graphType()
for name in ('Boston', 'Providence', 'New York', 'Chicago',
'Denver', 'Phoenix', 'Los Angeles'):
g.addNode(Node(name))
g.addEdge(Edge(g.getNode('Boston'), g.getNode('Providence')))
g.addEdge(Edge(g.getNode('Boston'), g.getNode('New York')))
g.addEdge(Edge(g.getNode('Providence'), g.getNode('Boston')))
g.addEdge(Edge(g.getNode('Providence'), g.getNode('New York')))
g.addEdge(Edge(g.getNode('New York'), g.getNode('Chicago')))
g.addEdge(Edge(g.getNode('Chicago'), g.getNode('Denver')))
g.addEdge(Edge(g.getNode('Chicago'), g.getNode('Phoenix')))
g.addEdge(Edge(g.getNode('Denver'), g.getNode('Phoenix')))
g.addEdge(Edge(g.getNode('Denver'), g.getNode('New York')))
g.addEdge(Edge(g.getNode('Los Angeles'), g.getNode('Boston')))
return g
def printPath(path):
"""Assumes path is a list of nodes"""
result = ''
for i in range(len(path)):
result = result + str(path[i])
if i != len(path) - 1:
result = result + '->'
return result
def BFS(graph, start, end):
initPath = [start]
pathQueue = [initPath]
while len(pathQueue) != 0:
tmpPath = pathQueue.pop(0)
lastNode = tmpPath[-1]
if lastNode == end:
return tmpPath
for nextNode in graph.childrenOf(lastNode):
if nextNode not in tmpPath:
newPath = tmpPath + [nextNode]
pathQueue.append(newPath)
return None