Breadth First Search是搜索图的最简单算法之一,
从Fool开始搜索
为了跟踪顶点的加入过程,并避免重复顶点,要为顶点增加3个属性
还需要用一个队列queue来对已发现的顶点进行排列
决定下一个要探索的顶点(队首顶点)
从起始顶点s开始,作为刚发现的顶点,标注为灰色,距离为0,前驱为None,加入队列,下面是循环迭代过程:
def bfs(g, start):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while vertQueue.size() > 0:
currentVert = vertQueue.dequeue()
for nbr in currentVert.getConnections():
if nbr.getColor() == 'white':
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance()+1)
vertQueue.enqueue(nbr)
currentVert.setColor('black')
BFS算法主体是两个循环的嵌套
while循环对每个顶点访问一次,所以是 O ( ∣ v ∣ ) \mathbf{O}(|\mathbf{v}|) O(∣v∣),而嵌套在while中的for,由于每条边只有在其其实顶点u出队的时候才会被检查一次,而每个顶点最多出队1次,所以边最多被检查1次,一共是 O ( ∣ E ∣ ) \mathbf{O}(|\mathbf{E}|) O(∣E∣),综合起来BFS的事件复杂度为 0 ( ∣ v ∣ + ∣ E ∣ ) 0(|v|+|E|) 0(∣v∣+∣E∣)
PS:
词梯文件被存在的地址是 : http://gis4g.pku.edu.cn/course/pythonds/#%E8%AF%BE%E7%A8%8B%E8%B5%84%E6%BA%90 你可以复制网址.在浏览器中打开上面的网址.并在打开的网页中搜索(CTRL+F)关键词 : 字母单词表. 之后,就可以找到一个压缩包.下载到本地并解压它就会得到文章代码所需要的词梯文件.希望回复及时 | |
下面代码建立图和顶点的类:
# coding: utf-8
from collections.abc import *
import sys
class Vertex:
def __init__(self, key):
self.id = key
self.connectedTo = {}
# 宽度优先遍历增加以下三个属性START----
self.color = 'white'
self.dist = sys.maxsize
self.pred = None
# 宽度优先遍历增加以下三个属性END----
# 深度优先遍历增加两个属性start------------
self.disc = 0
self.fin = 0
# 深度优先遍历增加两个属性end---------------
def addNeighbor(self, nbr, weight=0):
self.connectedTo[nbr] = weight
# 宽度优先增加方法start----------------
def setColor(self, color):
self.color = color
def setDistance(self, d):
self.dist = d
def setPred(self, p):
self.pred = p
def getPred(self):
return self.pred
def getDistance(self):
return self.dist
def getColor(self):
return self.color
# 宽度优先增加方法end----------------
# 深度优先增加方法 start---------------
def setDiscovery(self, dtime):
self.disc = dtime
def setFinish(self, ftime):
self.fin = ftime
def getFinish(self):
return self.fin
def getDiscovery(self):
return self.disc
# 深度优先增加方法 end---------------
# def __str__(self):
def __repr__(self):
return str(self.id) + 'connectedTo: ' + str([x.id for x in self.connectedTo])
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self, nbr):
return self.connectedTo[nbr]
# v1 = Vertex("good")
# v2 = Vertex("morning")
# v1.addNeighbor(v2)
# print(v2.getConnections())
# print(v1.getWeight(v2))
class Graph:
def __init__(self):
# 顶点形成的集合
self.vertList = {}
# 顶点的数目
self.numVertices = 0
def addVertex(self, key):
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex
return newVertex
def getVertex(self, n):
if n in self.vertList:
return self.vertList[n]
else:
return None
def __contains__(self, n):
return n in self.vertList
def addEdge(self, f, t, cost=0):
if f not in self.vertList:
nv = self.addVertex(f)
if t not in self.vertList:
nv = self.addVertex(t)
self.vertList[f].addNeighbor(self.vertList[t], cost)
def getVertices(self):
return self.vertList.keys()
def __iter__(self):
return iter(self.vertList.values())
if __name__ == '__main__':
g = Graph()
# print(isinstance(g, Iterator))
# print(isinstance(g, Iterable))
for i in range(6):
g.addVertex(i)
print(g.vertList)
g.addEdge(0, 1, 5)
g.addEdge(1, 2, 4)
g.addEdge(2, 3, 9)
g.addEdge(3, 4, 7)
g.addEdge(4, 0, 1)
g.addEdge(0, 5, 2)
g.addEdge(5, 4, 8)
g.addEdge(3, 5, 3)
g.addEdge(5, 2, 1)
# 下面的for调用__iter__函数
for v in g:
for w in v.getConnections():
print("(%s, %s)" % (v.getId(), w.getId()))
# print(g.vertList)
接下来利用图的广度优先搜索解决词梯问题:
# coding: utf-8
# from queue import Queue
# from pythonds.graphs import Graph, Vertex
import queue_orderdlist_ccc
import graph_ccc
def traverse(y):
x = y
# 当前驱不为None
print(x.getPred())
while x.getPred() is not None:
# 打印当前节点的id,就是这个单词
print(x.getId())
x = x.getPred()
print(x.getId())
def buildGraph(wordFile):
d = {}
g = graph_ccc.Graph()
wfile = open(wordFile, 'r')
# 采用字典建立桶
for line in wfile:
word = line[:-1]
# print("word++",word)
for i in range(len(word)):
bucket = word[:i] + '_' + word[i + 1:]
# print("bbbb", bucket)
if bucket in d:
d[bucket].append(word)
else:
d[bucket] = [word]
# add vertices and edges for words in the same bucket
for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1, word2)
return g
def bfs(g, start):
# print("kkkkkkkk", start)
start.setDistance(0)
start.setPred(None)
# print("ddddd",start.getDistance())
vertQueue = queue_orderdlist_ccc.Queue()
vertQueue.enqueue(start)
# 下面的while循环所有的顶点都放进去过一次
while vertQueue.size() > 0:
currentVert = vertQueue.dequeue()
for nbr in currentVert.getConnections():
# 说明还没有访问过
if nbr.getColor() == 'white':
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance() + 1)
nbr.setPred(currentVert)
vertQueue.enqueue(nbr)
currentVert.setColor('black')
if __name__ == '__main__':
# g = buildGraph('fourletterwords.txt')
# for item in g.vertList.values():
# print(item)
wordgraph = buildGraph("fourletterwords.txt")
bfs(wordgraph, wordgraph.getVertex('FOOL'))
traverse(wordgraph.getVertex('SAGE'))