22.1图的表示
图结构G(V,E)由顶点V和边E的集合组成,主要有邻接链表表示和邻接矩阵表示,两者的差别如下所示:
若为节点添加属性则可以通过改变节点自身的值,或者为节点添加属性或在节点中增加新的指针的方式来实现。权重也是属性的一种。
22.2 广度优先搜索
对于给定一个图中的原点,从原点出发按照到原点的距离来遍历所有的连通节点称为广度优先搜索。连接链表的算法广度优先搜索算法如下:
def ENQUEUE(Q, s):
Q.append(s)
def DEQUEUE(Q):
r = Q.pop(0)
return r
WHITE, GRAY, BLACK = (0, 1, 2)
class Vertex:
def __init__(self, u):
self.value = u
self.color = WHITE
self.d = float("inf")
self.pi = None
class Edge:
def __init__(self, u, v):
self.fromV = u
self.toV = v
class EdgeList:
def __init__(self, v):
self.vertex = v
self.connectedV = []
class Graph:
def __init__(self):
self.vertexs = {}
def CONNECT(u, v):
return Edge(u, v)
def INITGRAPH(G, edges):
for e in edges:
if not e.fromV.value in G.vertexs:
G.vertexs[e.fromV.value] = EdgeList(e.fromV)
if not e.toV.value in G.vertexs:
G.vertexs[e.toV.value] = EdgeList(e.toV)
G.vertexs[e.fromV.value].connectedV.append(e.toV)
G.vertexs[e.toV.value].connectedV.append(e.fromV)
def PRINTLIST(el):
print(el.vertex.value, ":")
for v in el.connectedV:
print(v.value)
def PRINTGRAPH(G):
for v in G.vertexs:
PRINTLIST(G.vertexs[v])
print("-----")
def BFS(G, s):
for v in G.vertexs:
if v != s.value:
G.vertexs[v].vertex.color = WHITE
G.vertexs[v].vertex.d = float("inf")
G.vertexs[v].vertex.pi = None
s.color = GRAY
s.d = 0
s.pi = None
Q = []
ENQUEUE(Q, s)
while len(Q) != 0:
u = DEQUEUE(Q)
for v in G.vertexs[u.value].connectedV:
if v.color == WHITE:
v.color = GRAY
v.d = u.d + 1
v.pi = u
ENQUEUE(Q, v)
u.color = BLACK
print(u.value, u.d)
def PRINT_PATH(G, s, v):
if v == s:
print(s.value)
elif v.pi == None:
print("no path from ", s.value, " to ", v.value, "exists")
else:
PRINT_PATH(G, s, v.pi)
print(v.value)
if __name__ == "__main__":
r = Vertex('r')
s = Vertex('s')
t = Vertex('t')
u = Vertex('u')
v = Vertex('v')
w = Vertex('w')
x = Vertex('x')
y = Vertex('y')
edges = []
edges.append(CONNECT(r, s))
edges.append(CONNECT(r, v))
edges.append(CONNECT(s, w))
edges.append(CONNECT(w, t))
edges.append(CONNECT(w, x))
edges.append(CONNECT(t, x))
edges.append(CONNECT(t, u))
edges.append(CONNECT(x, u))
edges.append(CONNECT(x, y))
edges.append(CONNECT(u, y))
G = Graph()
INITGRAPH(G, edges)
PRINTGRAPH(G)
print("**************")
BFS(G, s)
print("++++++++++++++")
PRINT_PATH(G, s, y)
我们采用循环不变式:queue中保存的节点到原点的距离为最短距离。采用书上的证明其正确性,概括如下:因为广度遍历的先将d小的加入queue中,当节点第一次被发现时其pi的距离+1即为最短距离。
22.3 深度优先搜索
类似与广度优先搜索,深度优先搜索算法沿着连接的边一路查找直到所有的连接点都已经发现在原路返回查找所有节点,实现如下:
def ENQUEUE(Q, s):
Q.append(s)
def DEQUEUE(Q):
r = Q.pop(0)
return r
WHITE, GRAY, BLACK = (0, 1, 2)
class Vertex:
def __init__(self, u):
self.value = u
self.color = WHITE
self.d = float("inf")
self.f = float("inf")
self.pi = None
class Edge:
def __init__(self, u, v):
self.fromV = u
self.toV = v
class EdgeList:
def __init__(self, v):
self.vertex = v
self.connectedV = []
class Graph:
def __init__(self):
self.vertexs = {}
def CONNECT(u, v):
return Edge(u, v)
def INITGRAPH(G, edges):
for e in edges:
if not e.fromV.value in G.vertexs:
G.vertexs[e.fromV.value] = EdgeList(e.fromV)
if not e.toV.value in G.vertexs:
G.vertexs[e.toV.value] = EdgeList(e.toV)
G.vertexs[e.fromV.value].connectedV.append(e.toV)
#G.vertexs[e.toV.value].connectedV.append(e.fromV)
def PRINTLIST(el):
print(el.vertex.value, ":")
for v in el.connectedV:
print(v.value)
def PRINTGRAPH(G):
for v in G.vertexs:
PRINTLIST(G.vertexs[v])
print("-----")
global time
time = 0
def DFS(G):
for u in sorted(G.vertexs.keys()):
G.vertexs[u].vertex.color = WHITE
G.vertexs[u].vertex.pi = None
global time
time = 0
for u in sorted(G.vertexs.keys()):
if G.vertexs[u].vertex.color == WHITE:
DFS_VISIT(G, G.vertexs[u].vertex)
def DFS_VISIT(G, u):
global time
time = time + 1
u.d = time
u.color = GRAY
for v in G.vertexs[u.value].connectedV:
if v.color == WHITE:
v.pi = u
DFS_VISIT(G, v)
u.color = BLACK
time = time + 1
u.f = time
print(u.value, u.d, u.f)
if __name__ == "__main__":
u = Vertex('u')
v = Vertex('v')
w = Vertex('w')
x = Vertex('x')
y = Vertex('y')
z = Vertex('z')
edges = []
edges.append(CONNECT(u, v))
edges.append(CONNECT(u, x))
edges.append(CONNECT(v, y))
edges.append(CONNECT(w, y))
edges.append(CONNECT(w, z))
edges.append(CONNECT(x, v))
edges.append(CONNECT(y, x))
edges.append(CONNECT(z, z))
G = Graph()
INITGRAPH(G, edges)
PRINTGRAPH(G)
print("===========")
DFS(G)
根据检索的边的连接点的不同,可以将边分为如下类型:
而且易证深度优先搜索有如下性质:
22.4 拓扑排序
拓扑排序就是无向环图的深度优先遍历中u.f值的由大到小的线性排序。
def ENQUEUE(Q, s):
Q.append(s)
def DEQUEUE(Q):
r = Q.pop(0)
return r
WHITE, GRAY, BLACK = (0, 1, 2)
class Vertex:
def __init__(self, u):
self.value = u
self.color = WHITE
self.d = float("inf")
self.f = float("inf")
self.pi = None
class Edge:
def __init__(self, u, v):
self.fromV = u
self.toV = v
class EdgeList:
def __init__(self, v):
self.vertex = v
self.connectedV = []
class Graph:
def __init__(self):
self.vertexs = {}
def CONNECT(u, v):
return Edge(u, v)
def INITGRAPH(G, edges):
for e in edges:
if not e.fromV.value in G.vertexs:
G.vertexs[e.fromV.value] = EdgeList(e.fromV)
if not e.toV.value in G.vertexs:
G.vertexs[e.toV.value] = EdgeList(e.toV)
G.vertexs[e.fromV.value].connectedV.append(e.toV)
#G.vertexs[e.toV.value].connectedV.append(e.fromV)
def PRINTLIST(el):
print(el.vertex.value, ":")
for v in el.connectedV:
print(v.value)
def PRINTGRAPH(G):
for v in G.vertexs:
PRINTLIST(G.vertexs[v])
print("-----")
global time
time = 0
def DFS(G, TG):
for u in sorted(G.vertexs.keys()):
G.vertexs[u].vertex.color = WHITE
G.vertexs[u].vertex.pi = None
global time
time = 0
for u in sorted(G.vertexs.keys()):
if G.vertexs[u].vertex.color == WHITE:
DFS_VISIT(G, G.vertexs[u].vertex, TG)
def DFS_VISIT(G, u, TG):
global time
time = time + 1
u.d = time
u.color = GRAY
for v in G.vertexs[u.value].connectedV:
if v.color == WHITE:
v.pi = u
DFS_VISIT(G, v, TG)
u.color = BLACK
time = time + 1
u.f = time
TG.append(u)
#print(u.value, u.d, u.f)
def TOPOLOGICAL_SORT(G):
TG = []
DFS(G, TG)
return TG
if __name__ == "__main__":
a = Vertex('a')
b = Vertex('b')
c = Vertex('c')
d = Vertex('d')
e = Vertex('e')
f = Vertex('f')
g = Vertex('g')
h = Vertex('h')
i = Vertex('i')
edges = []
edges.append(CONNECT(a, b))
edges.append(CONNECT(a, d))
edges.append(CONNECT(b, c))
edges.append(CONNECT(d, c))
edges.append(CONNECT(e, e))
edges.append(CONNECT(f, g))
edges.append(CONNECT(f, i))
edges.append(CONNECT(g, i))
edges.append(CONNECT(g, d))
edges.append(CONNECT(h, i))
G = Graph()
INITGRAPH(G, edges)
PRINTGRAPH(G)
print("===========")
TG = TOPOLOGICAL_SORT(G)
for u in TG:
print(u.value, u.d, u.f)
22.5 强连通分量
强连通分量其实就是环,把图G中的环归并到一起,就能将有环图变为无环图,无环图的许多算法可以被应用。如下图:
通过如下代码实现:
def ENQUEUE(Q, s):
Q.append(s)
def DEQUEUE(Q):
r = Q.pop(0)
return r
WHITE, GRAY, BLACK = (0, 1, 2)
class Vertex:
def __init__(self, u):
self.value = u
self.color = WHITE
self.d = float("inf")
self.f = float("inf")
self.pi = None
self.k = 0
class Edge:
def __init__(self, u, v):
self.fromV = u
self.toV = v
class EdgeList:
def __init__(self, v):
self.vertex = v
self.connectedV = []
class Graph:
def __init__(self):
self.vertexs = {}
def CONNECT(u, v):
return Edge(u, v)
def INITGRAPH(G, edges):
for e in edges:
if not e.fromV.value in G.vertexs:
G.vertexs[e.fromV.value] = EdgeList(e.fromV)
if not e.toV.value in G.vertexs:
G.vertexs[e.toV.value] = EdgeList(e.toV)
G.vertexs[e.fromV.value].connectedV.append(e.toV)
#G.vertexs[e.toV.value].connectedV.append(e.fromV)
def PRINTLIST(el):
print(el.vertex.value, ":")
for v in el.connectedV:
print(v.value)
def PRINTGRAPH(G):
for v in G.vertexs:
PRINTLIST(G.vertexs[v])
print("-----")
global time
time = 0
def DFS(G, TG, keys):
for u in keys:
G.vertexs[u].vertex.color = WHITE
G.vertexs[u].vertex.pi = None
global time
time = 0
k = 1
for u in sorted(G.vertexs.keys()):
if G.vertexs[u].vertex.color == WHITE:
DFS_VISIT(G, G.vertexs[u].vertex, TG, k)
k = k + 1
def DFS_VISIT(G, u, TG, k):
global time
time = time + 1
u.d = time
u.color = GRAY
for v in G.vertexs[u.value].connectedV:
if v.color == WHITE:
v.pi = u
DFS_VISIT(G, v, TG, k)
u.color = BLACK
time = time + 1
u.f = time
u.k = k
TG.append(u)
#print(u.value, u.d, u.f)
def TOPOLOGICAL_SORT(G, keys):
TSG = []
DFS(G, TSG, keys)
return TSG
def TRANSPOSE(G):
edges = []
for k in G.vertexs.keys():
u = G.vertexs[k].vertex
for v in G.vertexs[u.value].connectedV:
edges.append(CONNECT(v, u))
GT = Graph()
INITGRAPH(GT, edges)
return GT
def STRONGLY_CONNECTED_COMPONENTS(G, k):
GT = TRANSPOSE(G)
tsg = TOPOLOGICAL_SORT(G, k)
keys = []
for u in tsg:
keys.insert(0,u.value)
print(u.value)
gtts = []
DFS(GT, gtts, keys)
print("------------")
k = 0
for u in gtts:
if u.k != k:
print("|")
k = u.k
print(u.value)
if __name__ == "__main__":
a = Vertex('a')
b = Vertex('b')
c = Vertex('c')
d = Vertex('d')
e = Vertex('e')
f = Vertex('f')
g = Vertex('g')
h = Vertex('h')
edges = []
edges.append(CONNECT(a, b))
edges.append(CONNECT(b, c))
edges.append(CONNECT(b, e))
edges.append(CONNECT(b, f))
edges.append(CONNECT(c, d))
edges.append(CONNECT(c, g))
edges.append(CONNECT(d, c))
edges.append(CONNECT(d, h))
edges.append(CONNECT(e, a))
edges.append(CONNECT(e, f))
edges.append(CONNECT(f, g))
edges.append(CONNECT(g, f))
edges.append(CONNECT(g, h))
edges.append(CONNECT(h, h))
G = Graph()
INITGRAPH(G, edges)
PRINTGRAPH(G)
#STRONGLY_CONNECTED_COMPONENTS(G, ['c', 'g','f','h','d','b','e','a'])
keys = sorted(G.vertexs.keys())
print(keys)
STRONGLY_CONNECTED_COMPONENTS(G, keys)