杂
对图算法进行讨论需要引入一些约定。
给定 图G = (V, E)
当对此图上的算法的运行时间进行描述时,我们通常以
图的结点数|V| 和 边的条数|E|作为输入规模
仅在渐进记号中可用符号V、E代替
此外,伪码中用G.V表示图G的结点集,G.E表示图G的边集
两种表示方法
邻接链表和邻接矩阵,都可用于表示有向图和无向图。
邻接链表
通常使用邻接链表表示稀疏图
,即 |E| << |V|^2 的图。
无论表示有向图还是无向图,邻接链表的存储空间需求都是 Θ(V+E)
邻接链表的一个缺陷是无法快速判断一条 边(u, v)
是否存在于图中
唯一的办法是在邻接链表Adj[u]
中查找结点v
邻接矩阵
通常使用邻接矩阵表示稠密图。
无论一个图有多少条边,邻接矩阵的存储空间需求都是 Θ(V^2)
在表示无向图时可利用压缩矩阵来存储,其存储空间需求减少为邻接矩阵需求的一半
邻接矩阵克服了上述邻接链表的缺陷,但付出的存储代价增大。
在图规模比较小时,一般用邻接矩阵表示法更优
一是较简单,二是每个记录项仅需1位空间
无向图
以2号结点为例,在图上与1 5 4 3 相连
则邻接链表中,代表2号结点的链表由指向1 5 4 3结点的指针组成
邻接矩阵为对称矩阵
其他类似
所有邻接链表的长度和等于 2|E|,因为每条边都被计算了两次
有向图
以2号结点为例
邻接链表中,边 (2, 5)的5结点出现在2的链表中,而边(4, 2)的2结点会出现在4的链表中
邻接矩阵中,坐标为(2, 5)即代表边(2, 5)
其他类似
所有邻接链表的长度等于|E|,每条边在邻接链表表示法中仅计算一次
权重图
权重图是图中每条边都带有一个相关权重的图
用邻接链表表示时
边(u, v)的权重可以放在u的邻接链表里
用邻接矩阵表示时
边(u, v)的权重可以放在坐标为(u, v)的位置,如不存在则放None或0或…
图属性的表示
算法表示:如u.d表示结点u的属性d
程序实现:依赖因素较多。
如使用邻接链表表示图时,可以使用额外的数组表示结点属性。
如增设一个与Adj数组对应的数组d[1...|V|]
,如果与u邻接的结点都在Adj[u]
中,则可将结点u的属性存放到d[u]
的位置
原装Python实现
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author: 无名Joker
@time:2020/02/29
Purpose:
有向图和无向图的Python实现,每种图都使用邻接链表和邻接矩阵分别实现
Arguments:
Outputs:
本模块对外提供:
基于邻接链表的有向图类:DirectedGraphAL
基于邻接矩阵的有向图类:DirectedGraphAM
基于邻接链表的无向图类:UndirectedGraphAL
基于邻接矩阵的无向图类:UndirectedGraphAM
"""
# 基于邻接链表(AdjacencyList)的有向图(DirectedGraph)实现
class DirectedGraphAL:
def __init__(self):
# 使用字典内嵌集合的数据结构存放所有的邻接链表
# 每个邻接链表以 结点名: {其他结点名, 其他结点名} 的形式存放
self.adj = dict()
# 返回本图中所有邻接链表的key,即结点名
def get_vertices(self):
all_vertex_key = list()
for key in self.adj:
all_vertex_key.append(key)
return all_vertex_key
# 向图中添加新结点,u为结点名
def add_vertex(self, u):
if u in self.adj:
print("%r is already in the graph" % u)
else:
# 用set存放所有有向边(u, v)的v的结点名
self.adj[u] = set()
# 传入结点名,移除某结点及相关所有边
def remove_vertex(self, u):
if u not in self.adj:
print("%r is not in the graph" % u)
else:
# 移除本结点
del self.adj[u]
# 移除其他结点和本结点的边
for vtx in self.adj:
if u in self.adj[vtx]:
self.adj[vtx].remove(u)
# 增加一条有向边 (u, v)
def add_edge(self, u, v):
if u not in self.adj or v not in self.adj:
print("at least one vertex is not in the graph, failed to add this edge")
else:
self.adj[u].add(v)
# 移除有向边
def remove_edge(self, u, v):
if u not in self.adj or v not in self.adj:
print("this edge doesn't exist, failed to remove it")
else:
self.adj[u].remove(v)
# 返回某结点的所有邻接结点名
def get_neighbors(self, u):
if u not in self.adj:
print("%r is not in the graph" % u)
else:
return self.adj[u]
# 基于邻接矩阵的有向图类
class DirectedGraphAM:
def __init__(self):
# 用二重字典做邻接矩阵的存储
"""格式如
{
'1': {'1': 0, '2': 1},
'2': {'1': 1, '2': 0}
}
"""
self.matrix = dict()
# 返回所有结点名称
def get_vertices(self):
all_vertex_key = list()
for k in iter(self.matrix):
all_vertex_key.append(k)
return all_vertex_key
# 添加结点
def add_vertex(self, u):
if u not in self.matrix:
self.matrix[u] = dict()
else:
print("%r is already in the graph" % u)
# 删除结点
def remove_vertex(self, u):
if u not in self.matrix:
print("%r is not in the graph" % u)
else:
# 删除行
del self.matrix[u]
for v in self.matrix:
# 删除列
del self.matrix[v][u]
# 初始化邻接矩阵
def init_matrix(self):
for u in self.matrix:
for v in self.matrix:
# 每个结点与其他结点的距离初始化为无穷
self.matrix[u][v] = float("inf")
# 添加有向边(u, v)
def add_edge(self, u, v):
if u not in self.matrix or v not in self.matrix:
print("at least one vertex is not in the graph, failed to add this edge")
else:
self.matrix[u][v] = True
# 删除有向边
def remove_edge(self, u, v):
if u not in self.matrix or v not in self.matrix:
print("this edge doesn't exist, failed to remove it")
else:
self.matrix[u][v] = float("inf")
# 返回某结点的所有邻接结点名,有向
def get_neighbors(self, u):
if u not in self.matrix:
print("%r is not in the graph" % u)
else:
u_neighbors = list()
for nb in self.matrix[u]:
if self.matrix[u][nb] is True:
u_neighbors.append(nb)
return u_neighbors
# 基于邻接链表的无向图
class UndirectedGraphAL(DirectedGraphAL):
# 重写添加边的方法
def add_edge(self, u, v):
if u not in self.adj or v not in self.adj:
print("at least one vertex is not in the graph, failed to add this edge")
else:
# 双向添加
self.adj[u].add(v)
self.adj[v].add(u)
# 重写移除边的方法
def remove_edge(self, u, v):
if u not in self.adj or v not in self.adj:
print("this edge doesn't exist, failed to remove it")
else:
self.adj[u].remove(v)
self.adj[v].remove(u)
# 基于邻接矩阵的无向图
class UndirectedGraphAM(DirectedGraphAM):
# 重写 添加无向边(u, v)
def add_edge(self, u, v):
if u not in self.matrix or v not in self.matrix:
print("at least one vertex is not in the graph, failed to add this edge")
else:
self.matrix[u][v] = True
self.matrix[v][u] = True
# 重写 删除无向边
def remove_edge(self, u, v):
if u not in self.matrix or v not in self.matrix:
print("this edge doesn't exist, failed to remove it")
else:
self.matrix[u][v] = float("inf")
self.matrix[v][u] = float("inf")
if __name__ == '__main__':
"""
# 1.基于邻接链表的有向图
dgal = DirectedGraphAL()
# 添加六个结点
dgal.add_vertex("1")
dgal.add_vertex("2")
dgal.add_vertex("3")
dgal.add_vertex("4")
dgal.add_vertex("5")
dgal.add_vertex("6")
print(dgal.get_vertices())
# 删除结点时一并删除相关所有边
dgal.add_vertex("7")
dgal.add_edge("6", "7")
for ver in range(1, 7):
print(str(ver), dgal.get_neighbors(str(ver)))
print()
dgal.remove_vertex("7")
for ver in range(1, 7):
print(str(ver), dgal.get_neighbors(str(ver)))
print()
# 添加有向边
dgal.add_edge("1", "2")
dgal.add_edge("1", "4")
dgal.add_edge("2", "5")
dgal.add_edge("3", "5")
dgal.add_edge("3", "6")
dgal.add_edge("4", "2")
dgal.add_edge("5", "4")
dgal.add_edge("6", "6")
for ver in range(1, 7):
print(str(ver), dgal.get_neighbors(str(ver)))
print()
# 删除有向边
dgal.remove_edge("6", "6")
for ver in range(1, 7):
print(str(ver), dgal.get_neighbors(str(ver)))
"""
"""
# 2.基于邻接矩阵的有向图
dgam = DirectedGraphAM()
dgam.add_vertex("1")
dgam.add_vertex("2")
dgam.add_vertex("3")
dgam.add_vertex("4")
dgam.add_vertex("5")
dgam.add_vertex("6")
print(dgam.get_vertices())
print(dgam.matrix)
dgam.init_matrix()
for k in dgam.matrix:
print(k, dgam.matrix[k])
dgam.remove_vertex("1")
for k in dgam.matrix:
print(k, dgam.matrix[k])
print(dgam.get_neighbors('4'))
dgam.add_edge('4', '5')
print(dgam.get_neighbors('4'))
dgam.remove_edge('4', '5')
print(dgam.get_neighbors('4'))
"""
"""
# 3.基于邻接链表的无向图
ugal = UndirectedGraphAL()
ugal.add_vertex("1")
ugal.add_vertex("2")
ugal.add_vertex("3")
# 添加无向边
ugal.add_edge("1", "2")
ugal.add_edge("1", "3")
ugal.add_edge("2", "3")
for ver in range(1, 4):
print(str(ver), ugal.get_neighbors(str(ver)))
print()
# 删除无向边
ugal.remove_edge("2", "3")
for ver in range(1, 4):
print(str(ver), ugal.get_neighbors(str(ver)))
print()
"""
"""
# 4.基于邻接矩阵的无向图
ugam = UndirectedGraphAM()
ugam.add_vertex("1")
ugam.add_vertex("2")
ugam.add_vertex("3")
ugam.init_matrix()
ugam.add_edge("1", "2")
ugam.add_edge("1", "3")
ugam.add_edge("2", "3")
for k in ugam.matrix:
print(k, ugam.matrix[k])
print()
ugam.remove_edge("2", "3")
for k in ugam.matrix:
print(k, ugam.matrix[k])
print()
"""