図-幅優先探索(BFS)
幅優先探索は、グラフを検索するための最も単純なアルゴリズムの1つです。
- グラフGと、検索を開始する開始頂点sが与えられます。
- BFSは、sから頂点に到達するすべてのエッジを検索します。さらに距離がk + 1の頂点に到達する前に、BFSは距離がkのすべての頂点を検出します。
- これは、sをルートとしてツリーを構築し、レベルを上から下に徐々に上げるプロセスとして想像できます。
- 幅優先探索では、レベルを上げる前に、すべての兄弟ノードがツリーに追加されていることを確認できます。
-
愚か者から検索
-
頂点の追加プロセスを追跡し、頂点の繰り返しを回避するために、3つの属性が頂点に追加されます
- 距離:開始頂点からこの頂点までのパスの長さ
- 前任者:開始点までさかのぼることができます
- 色:この頂点がまだ検出されていないか(白)、検出されているか(灰色)、探索されているか、探索されているか(黒)を識別します。
-
また、キューを使用して、見つかった頂点を配置する必要があります
-
探索する次の頂点を決定します(チームの一番上の頂点)
-
開始頂点sから開始して、頂点が検出されたばかりの場合、頂点は灰色でマークされ、距離は0、先行頂点はNoneであり、キューに追加されます。ループ反復プロセスは次のとおりです。
- チームの先頭から頂点を現在の頂点として取得します。
- 現在の頂点の隣接する頂点をトラバースします。未検出の白い頂点の場合は、色を灰色(検出済み)に変更し、距離を1増やします。前の頂点が現在の頂点になります。トラバースが完了したら、現在の頂点を設定します。キューへの頂点黒、ステップ1でチームの最初にループバックして、現在の頂点を取得します
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アルゴリズムの本体は、2つのループのネストです。
whileループは各頂点に1回アクセスするため、O(∣ v∣)\ mathbf(O)(| \ mathbf(v)|)O(| V | )、および各エッジは一度だけその頂点uが実際にデキューされたときにチェックされ、エッジが最もチェック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 URLをコピーできます。ブラウザで上記のURLを開き、開いたWebページで検索(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'))