目录
1、图遍历
2、最小生成树-Prime算法
3、最短路径-Dijkstra算法
图的两种常用的表示方式是邻接矩阵和邻接表。以下以邻接矩阵为例,图的初始化定义:
class Graph():
def __init__(self,nodeNum,sides,direction=False):
self.nodeNum = nodeNum #顶点
self.amatrix = [[0]*(nodeNum+1) for i in range(nodeNum+1)] #邻接矩阵
for side in sides:
u,v,w = side
if(direction):
self.amatrix[u][v]=w
else:
self.amatrix[u][v]=w
self.amatrix[v][u]=w
在图遍历时,有两种常用的访问顶点的顺序,深度优先遍历和广度优先遍历。以下图为例,深度优先遍历的结点为:1、2、3、4、6、5、7、8、9,广度优先遍历的结点为:1、2、3、5、4、7、8、6、9.
深度优先遍历的迭代版本如下:
def dfs(graph,v):
visitnodes.append(v)
for j in range(graph.nodeNum+1):
if((graph.amatrix[v][j]>0) and (j not in visitnodes)):
dfs(graph,j)
graph = Graph(9,[[1,2,1],[2,3,1],[3,4,1],[2,5,1],[4,6,1],[5,7,1],[5,8,1],[8,9,1]])
visitnodes = []
dfs(graph,1)
print(visitnodes)
[1, 2, 3, 4, 6, 5, 7, 8, 9]
生成树拥有最少的边,保持各顶点之间的连通性,如果区域中包含了n个顶点,生成树包含n-1条边。最小生成树,将生成树边的权重加和最小的生成树。Prime算法,从已连通区域和未连通区域链接的边中,选择一条权重最小的边,加入到生成树中,已下图为例,加入到生成树中的边以此为:1->2,1->3, 3->4, 4->6, 6->5.
#最小生成树--prime算法(借用堆存储边)
import heapq
def getMinimumSpanningTree(graph,v):
minimumSpanningTree = []
visitnodes.append(v)
edges = []
for j in range(graph.nodeNum+1): #从节点v出发的边入堆
if(graph.amatrix[v][j]>0):
heapq.heappush(edges,[graph.amatrix[v][j],v,j])
k=1
while(k < graph.nodeNum):
w,vi,vj = heapq.heappop(edges) #输出权重最小的一条边
if (vj not in visitnodes): #若该边链接的节点未被访问,将节点vj出发的边插入堆中
minimumSpanningTree.append([vi,vj,w])
visitnodes.append(vj)
for i in range(graph.nodeNum+1):
if(graph.amatrix[vj][i]>0):
heapq.heappush(edges,[graph.amatrix[vj][i],vj,i])
k=k+1
return minimumSpanningTree
graph = Graph(6,[[1,2,1],[1,3,2],[2,4,11],[2,3,6],[3,4,9],[3,5,13],[4,5,7],[4,6,3],[5,6,4]])
visitnodes = []
minimumSpanningTree = getMinimumSpanningTree(graph,1)
print(minimumSpanningTree)
[[1, 2, 1], [1, 3, 2], [3, 4, 9], [4, 6, 3], [6, 5, 4]]
该算法计算从源结点到图中所有其他顶点之间的最短路径的距离,重复地选取那些还没有被包含且具有最短路径距离的顶点。算法的输出是results是一维数组,元素值是下标对应顶点到源顶点的距离,还使用一个中间变量included,记录是否查找到对应顶点到源顶点的最短距离。
#单源点的最短路径问题--dijkstra算法
import math
def getMinDistance(graph,v):
#初始化results,included
results = [math.inf] * (graph.nodeNum+1)
results[v] = 0
included = [False]*(graph.nodeNum+1)
included[v] = True
for i in range(graph.nodeNum+1):
if(graph.amatrix[v][i]>0):
results[i] = graph.amatrix[v][i]
while(included.count(True) < graph.nodeNum):
mindata = math.inf
includenode = 0 #选取未获得最短路径(include[v]=false)且results[v]最小的结点,源结点到该结点v的最短路径已找到
for i in range(len(results)):
if((not math.isinf(results[i])) and (not included[i]) and (mindata > results[i])):
mindata = results[i]
includenode = i
included[includenode]=True
for i in range(graph.nodeNum+1): #根据结点v出发的边,更新源结点到v链接结点的距离。
if(graph.amatrix[includenode][i] > 0):
newdistance = results[includenode] + graph.amatrix[includenode][i]
if(newdistance < results[i]):
results[i] = newdistance
return results
graph = Graph(6,[[1,2,1],[1,3,12],[2,3,9],[2,4,3],[3,5,5],[4,3,4],[4,5,13],[4,6,15],[5,6,4]],True)
results = getMinDistance(graph,1)
print(results)
[inf, 0, 1, 8, 4, 13, 17]
参考资料:
数据结构《python语言描述》