1 邻接矩阵
种类:一维数组和二维数组
一维数组:存储图中顶点自身的信息
二维数组:存储图中顶点间邻接关系的矩阵
2 最小生成树
生成树:连通图的生成树是包含全部顶点的一个极小连通子图,可用DFS和BFS生成。
生成树的代价:在无向连通网中,生成树上各边的权值之和
最小生成树:在无向连通网中,代价最小的生成树
性质:各边权值互不相等时,最小生成树是唯一的,边数为顶点数-1
3 Prim算法
定义:从没一个顶点开始构建生成树,每次将代价最小的顶点纳入生成树,直到所有顶点都纳入为止(基于贪心算法)
python代码如下所示:
其中实现每次取出代价最小的边时,这里采用sort()内置函数,复杂度为O(nlogn),当图过大时,可能效果较差,可以使用heapq函数库,使用小根堆的结构,来优化,这样每次更新时,复杂度为O(logn)
from collections import defaultdict
def prim(vertex,egdes,start='A'):
adiacent = defaultdict(list)
for weight,v1,v2 in egdes:
adiacent[v1].append([weight,v1,v2])
adiacent[v2].append([weight,v2,v1])
minu_tree = []
visited = set()
visited.add(start)
stack = [i for i in adiacent[start]]
while stack:
stack.sort(key=lambda x:x[0])
cur_minpath = stack.pop(0)
if cur_minpath[2] not in visited:
visited.add(cur_minpath[2])
minu_tree.append(cur_minpath)
for next_path in adiacent[cur_minpath[2]]:
stack.append(next_path)
return minu_tree
vertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
edges = [(7, 'A', 'B'),
(5, 'A', 'D'),
(8, 'B', 'C'),
(9, 'B', 'D'),
(7, 'B', 'E'),
(5, 'C', 'E'),
(15, 'D', 'E'),
(6, 'D', 'F'),
(8, 'E', 'F'),
(9, 'E', 'G'),
(11, 'F', 'G')]
print(prim(vertices, edges, start='D'))
4 Dijkstra算法
基本原理:该算法是基于广度优先搜索的,适用于带权图和非带权图,不适用于带负权的图。
基本步骤:
1.找出当前离起点最近的节点
2.对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新,并更新邻居的父节点
3.重复过程2,直至遍历全部节点
4.计算最终路径
举个例子:如下图所示,如果想要计算点D到各个节点的最短路径,则需要按照上述公式一次遍历更新。
首先定义一个矩阵长为图中点的个数:[inf, inf, inf, 0, inf, inf, inf],除了出发点自身下标对应值设置为0意外,其余全为无穷大。
然后遍历与D相邻的所有点,更新对应距离,如D与C之间为3,与E之间为4,故更新之后矩阵为[inf, inf, 3, 0, 4, inf, inf],此时下一轮遍历的点为(C,E),接着遍历与C相邻的所有点(B,F,E),得到矩阵[inf, 13, 3, 0, 4, 9, inf],此时下一轮遍历的点为(E,B,F),然后遍历E,得到矩阵[inf, 13, 3, 0, 4, 6, 12],可以发现D到F的值更新了。
python实现代码如下:
from collections import defaultdict
def dijstra(nodes,edges,ip='A'):
mapper = defaultdict(list)
node_num = len(nodes)
path = [float('inf')]*node_num
for start,end,weight in edges:
mapper[start].append([end,weight])
mapper[end].append([start,weight])
path[ord(ip)-ord('A')]=0
print(path)
visited = set()
visited.add(ip)
stack = [ip]
while stack:
node = stack.pop(0)
for next_node,weight in mapper[node]:
path[ord(next_node)-ord('A')]=min(path[ord(next_node)-ord('A')],path[ord(node)-ord('A')]+weight)
if next_node not in visited:
stack.append(next_node)
visited.add(next_node)
print(path)
return path
nodes = 'ABCDEFG'
egdes = [
['A','B',12],['A','F',16],['A','G',14],['B','C',10],
['B','F',7],['C','F',6],['C','D',3],['C','E',5],
['F','G',9],['F','E',2],['E','G',8],['E','D',4]
]
res = dijstra(nodes,egdes,ip='D')
print(res)
下期将更新Floyd 算法,以及实现检测图中是否有环的情形。