本文基于书籍《算法》第四版,并且结合了网络上的代码和解决方案
环境:
win10
python3.9
pycharm
库:
import queue from collections import deque
现规定
```python
.
.python代码
.
```
无向图API
```python
#实现的功能:
# Graph(n)创建一个含有n个节点的邻接表
# Graph.getNumberOfEdge 返回边数
# Graph.getNumberOfVertex 返回顶点数
# Graph.addEdge(v,w) 添加连接v和w的边
# Graph.print_graph打印邻接表
# Graph.adj(v) 返回与v相邻的顶点列表
#无向图API,邻接表表示这里采用list嵌套list实现
class Graph:
def __init__(self,n): #输入n,初始化长度为n的邻接表
self.n = n # number of vertex
self.m = 0 #number of edge
self.matrix = [[] for x in range(n)] #初始化邻接表
def getNumberOfEdge(self): #返回边数
return self.m
def getNumberOfVertex(self): #返回顶点数
return self.n
def addEdge(self,v,w): #添加边
if 0 <= v <= self.n and 0 <= w <= self.n:
self.matrix[v].append(w)
self.matrix[w].append(v)
self.m=self.m+1
def print_graph(self): #打印邻接表
for i in range(self.n):
nei=[]
for j in range(len(self.matrix[i])):
nei.append(self.matrix[i][j])
print(str(i) + "和这些点连接"+str(nei))
def adj(self,v): #返回相邻顶点
return self.matrix[v]
#测试代码
g=Graph(6)
g.addEdge(2,3)
g.addEdge(2,1)
g.addEdge(4,5)
g.addEdge(3,4)
print("顶点个数"+str(g.getNumberOfEdge()))
print("边个数"+str(g.getNumberOfVertex()))
g.print_graph()
print("索引为3的顶点的相邻顶点"+str(g.adj(3)))
# 输出结果:
# 顶点个数4
# 边个数6
# 0和这些点连接[]
# 1和这些点连接[2]
# 2和这些点连接[3, 1]
# 3和这些点连接[2, 4]
# 4和这些点连接[5, 3]
# 5和这些点连接[4]
# 索引为3的顶点的相邻顶点[2, 4]
```
深度优先搜索
```python
#实现的功能:
# DeptFirstSearch(G,s) 输入图像和搜素的起点
# DeptFirstSearch.boolen_mark(w) 查询w点是否被标记
# DeptFirstSearch.count() 返回遍历的点数
#深度优先搜索
class DepthFirstSearch:
def __init__(self,G,s):
self.marked=[False for i in range(G.getNumberOfVertex())] #创建标记表,搜索过的点表位True,否则为False
self.count_=0 #节点个数
self.dfs(G,s) #调用深度优先搜索
def dfs(self,G,v):
self.marked[v]=True
self.count_=self.count_+1
for w in G.adj(v): #对图G中点v的相邻点执行相同操作
if(self.marked[w]!=True):
self.dfs(G,w) #递归。
#这里详细讲一下,会一直递归下去,递归一次就会深入一层,没有为标记的点时就返回上一层,到下一个相邻的节点继续递归。因为是先深入,没有路了才返到上一个路口,所以叫深度优先。
def boolen_marked(self,w): #查询某点是否被标记
return self.marked[w]
def count(self): #返回搜索的点数
return self.count_
#测试代码
#g为上一个图算法的g
D=DepthFirstSearch(g,2) #输入该图和起点
print("编号为3的点搜索情况"+str(D.boolen_marked(3)))
print("搜索到的点数"+str(D.count()))
#输出结果
# 编号为3的点搜索情况True
# 搜索到的点数5
```
广度优先算法
```python
#广度优先搜索
#实现的功能
# BreadthFirstPaths(G,s) 输入一幅图和搜素的起点初始化
# BreadthFirstPaths.hasPathTo(v) 检测v和起点是否相通
# BreadthFirstPaths.pathTo(v) 获得起点到v的路径
import queue #导入队列模块
from collections import deque #导入栈模块
class BreadthFirstPaths:
def __init__(self,G,s): #初始化
self.marked=[False for i in range(G.getNumberOfVertex())] #标记列表
self.edgeTo=[0 for i in range(G.getNumberOfVertex())] #路径记录列表,记录通往改点的上一点即可
self.s=s #记录起点
self.path = deque() #创建队列,后面要用
self.bfs(G,s) #调用函数实现广度优先
def bfs(self,G,s): #广度优先函数
queue_=queue.Queue() #创建队列
self.marked[s]=True #起点设为已标记
queue_.put(s) #将起点加入队列
while(queue_.empty()!=True): #当队列不为空时
v=queue_.get() #将队列最后一个元素取出
for w in G.adj(v) : #遍历v的相邻节点
if(self.marked[w]!=True): #如果改点没有标记
self.edgeTo[w]=v #改点上一个连接点设为v
self.marked[w]=True #设为已标记
queue_.put(w) #将它加入队列
def hasPathTo(self,v):
return self.marked[v] #返回该点是否被标记
def pathTo(self,v): #利用栈记录递归从队列中得到的路径
if(self.hasPathTo(v)!=True):#如果该点连通,返回空值
return
self.path.append(v) # 向栈中添加终点
self.getpath(v) #带入终点,递归,获得路径
return self.path
def getpath(self,x): #获得路径的算法
if x!=self.s: #如果和起点不相同
x=self.edgeTo[x] #得到x点的上一点并赋值于x
self.path.append(x) #将x添加如栈
self.getpath(x) #再次递归
#测试代码
B=BreadthFirstPaths(g,1) #输入图g和起点1
print("起到到3连通吗"+str(B.hasPathTo(3)))
print("从起点到5的路径为"+str(B.pathTo(5)))
# 输出结果
# 起到到3连通吗True
# 从起点到5的路径为deque([5, 4, 3, 2, 1])
```
获得连通分量的实现
```python
#连通分量指的是,一副图里面有多少个不相互连通的部分
#实现的功能:
# CC(G) 输入一副图
# CC.bool_connected(v,w) v和w是否连通,返回值为布尔类型
# CC.get_id(v) 得到v点的连通分量标号
# CC.get_count() 得到改图的连通分量
#连通分量(使用深度学习优先搜索找出图中所有连通分量)
class CC:
def __init__(self,G):
self.count=0 #用于计算连通分量的数量
self.marked=[False for i in range(G.getNumberOfVertex())] #用来记录点是否标记
self.id=[0 for i in range(G.getNumberOfVertex())] #用来记录各个点的连通分量代号
for s in range(G.getNumberOfVertex()): #对图的每个点遍历
if(self.marked[s]!=True):
#若没有标记就使用深度优先搜索,然后给各个标记上。这
# 个部分有意思,以为每个点都要来一次,其实一次深度优先,许多点都会标记上,不会再次深度优先的
self.dfs(G,s)
self.count=self.count+1
def dfs(self, G, v): #深度优先算法,前面讲过了,不在记录了
self.marked[v] = True
self.id[v]=self.count
for w in G.adj(v): # 对图G中点v的相邻点执行相同操作
if (self.marked[w] != True):
self.dfs(G, w)
def bool_connected(self,v,w): #返回是否连通,是一个布尔值。如果处于同一个连通分量就是连通的。
return self.id[v]==self.id[w]
def get_id(self,v): #得到某点的连通分量
return self.id[v]
def get_count(self): #得到连通分量的个数
return self.count
#测试代码
c=CC(g)
print("连通分量的数量是"+str(c.get_count()))
print("点0和5相通吗"+str(c.bool_connected(0,5)))
#输出结果
# 连通分量的数量是1
# 点0和5相同吗True
```
是否成环
```python
#解决成环问题,即回答一幅图是否是无环图
#实现的功能
# Cycle(G) 传入一幅图
# Cycle.bool_hasCycle 返回是否成环
class Cycle:
def __init__(self,G):
self.marked=[False for i in range(G.getNumberOfVertex())]
self.hasCycle=False
for s in range(G.getNumberOfVertex()): # 对图的每个点遍历
if (self.marked[s] != True):
# 若没有标记就使用深度优先搜索,然后给各个标记上。这
# 个部分有意思,以为每个点都要来一次,其实一次深度优先,许多点都会标记上,不会再次深度优先的
self.dfs(G, s,s)
def dfs(self, G, v,u): # 深度优先算法,前面讲过了,不在记录了
self.marked[v] = True
for w in G.adj(v): # 对图G中点v的相邻点执行相同操作
if (self.marked[w] != True):
self.dfs(G, w,v)
elif w!=u: #这个算法检测是否成环的原理就是多传导一个参数来记录前一个点,
# 再加一个判断条件,如果深入的时候,碰到了标记过的点,却又不是前一个点,那么他就成环了
self.hasCycle=True
def bool_hasCycle(self):
return self.hasCycle
#测试代码,因为前面的代码都是没有成环的,所以我们重新创建一个有环的图
g=Graph(6)
g.addEdge(0,5)
g.addEdge(2,3)
g.addEdge(2,1)
g.addEdge(4,5)
g.addEdge(3,4)
g.addEdge(0,4)
cy=Cycle(g)
print("成环吗"+str(cy.bool_hasCycle()))
#输出结果
# 成环吗True
```
是二分图吗?双色问题
```python
#双色问题
#实现的功能
# TwoColor(G) 输入一幅图
# TwoColor.bool_isBipartite() 返回是否满足双色问题的布尔值
class TwoColor:
def __init__(self,G):
self.marked=[False for i in range(G.getNumberOfVertex())]
self.color=[False for i in range(G.getNumberOfVertex())]
self.isTwoColorable=True
for s in range(G.getNumberOfVertex()): # 对图的每个点遍历
if (self.marked[s] != True):
# 若没有标记就使用深度优先搜索,然后给各个标记上。这
# 个部分有意思,以为每个点都要来一次,其实一次深度优先,许多点都会标记上,不会再次深度优先的
self.dfs(G, s,)
def dfs(self, G, v): # 深度优先算法,前面讲过了,不在记录了
self.marked[v] = True
for w in G.adj(v): # 对图G中点v的相邻点执行相同操作
if (self.marked[w] != True):
self.color[w]=not self.color[v]
self.dfs(G, w)
elif self.color[w]==self.color[v]:
self.isTwoColorable=False
def bool_isBipartite(self):
return self.isTwoColorable
#测试代码
tc=TwoColor(g) #使用的是上一个算法有环的那个图
print("双色问题满足吗"+str(tc.bool_isBipartite()))
#输出结果
#双色问题满足吗False
```
有向图
```python
#有向图
#和无向图类似,多了个reverse,且只添加了一次边
class Digraph:
def __init__(self,n): #输入n,初始化长度为n的邻接表
self.n = n # number of vertex
self.m = 0 #number of edge
self.matrix = [[] for x in range(n)] #初始化邻接表
def getNumberOfEdge(self): #返回边数
return self.m
def getNumberOfVertex(self): #返回顶点数
return self.n
def addEdge(self,v,w): #添加边
if 0 <= v <= self.n and 0 <= w <= self.n:
self.matrix[v].append(w)
self.m=self.m+1
def print_graph(self): #打印邻接表
for i in range(self.n):
nei=[]
for j in range(len(self.matrix[i])):
nei.append(self.matrix[i][j])
print(str(i) + "和这些点连接"+str(nei))
def adj(self,v): #返回相邻顶点
return self.matrix[v]
def reverse(self):
R=Digraph(self.n)
for v in range(self.n):
for w in self.adj(v):
R.addEdge(w,v)
return R
```
有向图的可达性
```python
#有向图的可达性
#实现的功能
# DirectedDFS(G,s) 输入图和搜索起点,初始化算法
# DirectedDFS(G,s).bool_marked(v) 判断v和s是否连通,返回值为布尔类型
class DirectedDFS:
def __init__(self,G,s:int):
self.marked=[False for i in range(G.getNumberOfVertex())]
if(isinstance(s, list)):
for x in s:
if (self.marked[x] != True):
self.dfs(G, x)
else:
self.dfs(G, s)
def dfs(self,G,v):
self.marked[v]=True
for w in G.adj(v):
if self.marked[w]!=True:
self.dfs(G,w)
def bool_marked(self,v):
return self.marked[v]
#测试代码
#创建一副有向图
D=Digraph(5)
D.addEdge(0,1)
D.addEdge(2,1)
D.addEdge(1,3)
D.addEdge(1,4)
DD=DirectedDFS(D,0) #从起点0开始搜索,标记所有与他相邻的顶点
print(DD.marked) #打印标记情况
print("0和2是否连通"+str(DD.bool_marked(2)))
DD_=DirectedDFS(D,[2,0]) #从起点2,0开始搜索,标记所有与他们相邻的顶点
print(DD_.marked) #打印标记情况
print("0,2和2是否连通"+str(DD_.bool_marked(2)))
#输出结果
# [True, True, False, True, True]
# 0和2是否连通False
# [True, True, True, True, True]
# 0,2和2是否连通True
```
寻找有向环
```python
#寻找有向环
#实现的功能
# DirectedCycle(D) 带入有向图实例化对象
# DirectedCycle.getCycle() 得到环,返回的是一个栈类型(双向队列)
from collections import deque #导入栈模块
class DirectedCycle:
def __init__(self,G):
self.cycle = deque()
self.onStack=[False for i in range(G.getNumberOfVertex())]
self.edgeTo=[0 for i in range(G.getNumberOfVertex())]
self.marked=[False for i in range(G.getNumberOfVertex())]
self.Stack=deque()
for v in range(G.getNumberOfVertex()):
if self.marked[v]!=True:
self.dfs(G,v)
def dfs(self,G,v):
self.onStack[v]=True
self.marked[v]=True
for w in G.adj(v):
if self.cycle: #如果环存在,直接返回
return
elif self.marked[w]!=True: #如果遇到没有标记的点,将它标记
self.edgeTo[w]=v
self.dfs(G,w)
elif self.onStack[w]==True: #这里这个设计很妙,采用了OnStack来记录沿途,先对搜索过的点标记为True,如果深度搜索没有路了,返回上一层又改回FALSE。
#所以没有环的话,遍历的过程中是不会碰到下一个目标点的onStack为True的情况,如果碰到,说明程序返回不了上一层,就成环了。
self.addCycle(v,w)
self.cycle.append(v)
self.onStack[v]=False
def addCycle(self,x,w): #获得路径的算法
if x!=w: #如果和起点不相同
x=self.edgeTo[x] #得到x点的上一点并赋值于x
self.cycle.append(x) #将x添加如栈
self.addCycle(x,w) #再次递归
def getCycle(self):
return self.cycle
#测试代码
#创建一副有向图
D=Digraph(5)
D.addEdge(0,1)
D.addEdge(2,1)
D.addEdge(1,3)
D.addEdge(1,4)
D.addEdge(4,2)
DS=DirectedCycle(D) #实例化类
print("环:"+str(DS.getCycle())) #得到环
#输出结果
# 环:deque([4, 1, 2])
```
基于深度优先的顶点排序
```python
#实现的功能
#在不同的时刻记录标记的点,存入队列和栈
import queue
from collections import deque
class DepthFirstOrder:
def __init__(self,G):
self.pre=queue.Queue()
self.post=queue.Queue()
self.reversePost=deque()
self.marked=[False for i in range(G.getNumberOfVertex())]
for v in range(G.getNumberOfVertex()):
if self.marked[v]!=True:
self.dfs(G,v)
def dfs(self,G,v):
self.pre.put(v)
self.marked[v]=True
for w in G.adj(v):
if(self.marked[w]!=True):
self.dfs(G,w)
self.post.put(v)
self.reversePost.append(v)
def get_pre(self):
return self.pre
def get_post(self):
return self.post
def get_reversePost(self):
return self.reversePost
#测试代码
D=Digraph(5)
D.addEdge(0,1)
D.addEdge(2,1)
D.addEdge(1,3)
D.addEdge(1,4)
DO=DepthFirstOrder(D)
#输出pre 前序
print("前序")
while DO.get_pre().empty()!=True:
print(DO.get_pre().get())
print("---------------------------------------------")
#输出post 后序
print("后序")
while DO.get_post().empty()!=True:
print(DO.get_post().get())
print("---------------------------------------------")
#输出reversePost 栈
print("栈")
while DO.get_reversePost():
print(DO.get_reversePost().pop())
#输出结果
# 前序
# 0
# 1
# 3
# 4
# 2
# ---------------------------------------------
# 后序
# 3
# 4
# 1
# 0
# 2
# ---------------------------------------------
# 栈
# 2
# 0
# 1
# 4
# 3
```
有向图的强连通性
```python
#连通分量(使用深度学习优先搜索找出图中所有连通分量)
class KosarajuSCC:
def __init__(self,G):
self.count=0 #用于计算连通分量的数量
self.marked=[False for i in range(G.getNumberOfVertex())] #用来记录点是否标记
self.id=[0 for i in range(G.getNumberOfVertex())] #用来记录各个点的连通分量代号
self.order=DepthFirstOrder(G.reverse())
for s in list(self.order.get_reversePost()): #对图的每个点遍历
if(self.marked[s]!=True):
#若没有标记就使用深度优先搜索,然后给各个标记上。这
# 个部分有意思,以为每个点都要来一次,其实一次深度优先,许多点都会标记上,不会再次深度优先的
self.dfs(G,s)
self.count=self.count+1
def dfs(self, G, v): #深度优先算法,前面讲过了,不在记录了
self.marked[v] = True
self.id[v]=self.count
for w in G.adj(v): # 对图G中点v的相邻点执行相同操作
if (self.marked[w] != True):
self.dfs(G, w)
def bool_stronglyconnected(self,v,w): #返回是否连通,是一个布尔值。如果处于同一个连通分量就是连通的。
return self.id[v]==self.id[w]
def get_id(self,v): #得到某点的连通分量
return self.id[v]
def get_count(self): #得到连通分量的个数
return self.count
#测试代码
D=Digraph(5)
D.addEdge(0,1)
D.addEdge(2,1)
D.addEdge(1,3)
D.addEdge(1,4)
D.addEdge(4,1)
KSCC=KosarajuSCC(D)
print("连通分量的数量是"+str(KSCC.get_count()))
print("点0和2强相通吗"+str(KSCC.bool_stronglyconnected(0,2)))
print("点1和4强相通吗"+str(KSCC.bool_stronglyconnected(1,4)))
#输出结果
# 连通分量的数量是2
# 点0和2强相通吗False
# 点1和4强相通吗True
```
在原书中有一段再谈可达性,我不太清楚是什么意思,和前面写过的DirectedDFS差不多,不重点讨论了。
带权重的边的数据类型
```python
# 实现的功能
# Edge(v,w,weight) 设置边的起点、终点、权重
# Edge.get_weight() 返回边的权重
# Edge.get_either() 返回边的起点
# Edge.order(vertex) 返回另一个顶点
# Edge.compareTo(that) 和另一条边比较
# Edge.toString() 打印边
class Edge:
def __init__(self,v,w,weight): #设置边的起点、终点、权重
self.v=v
self.w=w
self.weight=weight
def get_weight(self): #返回边的权重
return self.weight
def get_either(self): #返回边的起点
return self.v
def order(self,vertex): #返回另一个顶点
if vertex==self.v:
return self.w
if vertex==self.w:
return self.v
def compareTo(self,that): #和另一条边比较
if self.weight<that.weight:
return -1
elif self.weight>that.weight:
return +1
else:
return 0
def toString(self): #打印边
return str.format("%d-%d %.2f"%(self.v,self.w,self.weight))
#测试代码
Eg=Edge(2,3,5)
Eg_=Edge(1,4,7)
print(Eg.get_weight()) #返回权重
print(Eg.order(3)) #返回和3相连的另一点
print(Eg.get_either()) #返回边的出发点
print(Eg_.get_weight()) #返回权重
print(Eg_.order(4)) #返回和4相连的另一点
print(Eg_.get_either()) #返回边的出发点
print(Eg.compareTo(Eg_)) #返回边的权重比较结果
print(Eg.toString()) #打印边
print(Eg_.toString()) #打印边
#输出结果
# 5
# 2
# 2
# 7
# 1
# 1
# -1
# 2-3 5.00
# 1-4 7.00
```
加权无向图的数据类型
```python
#功能注释在方法旁边了,接下来都这样子写。
class EdgeWeightedGraph:
def __init__(self,v): #初始化
self.v=v
self.e=0
self.adj=[[]for i in range(v)]
def addEdge(self,e): #添加边
v=e.get_either()
w=e.order(v)
self.adj[v].append(e)
self.adj[w].append(e)
self.e=self.e+1
def V(self):
return self.v
def E(self):
return self.e
def adj_(self,v): #获得所有相邻边
return self.adj[v]
#创建一系列有权边
Eg=Edge(2,3,5)
Eg_=Edge(1,4,7)
Eg_2=Edge(4,2,3)
Eg_3=Edge(0,1,2)
#初始化加权无向图并添加边
EWG=EdgeWeightedGraph(5)
EWG.addEdge(Eg)
EWG.addEdge(Eg_)
EWG.addEdge(Eg_2)
EWG.addEdge(Eg_3)
#返回与4点相邻的点的第一个点的起点
print(EWG.adj_(4)[0].get_either())
#输出结果
1
最小生成树Prim算法的延迟实现
```python
#实现的功能输入一幅图就可以找到他的最小连通树
import queue
class LazyPrimMST:
def __init__(self,G):
self.pq=[]
self.marked=[False for i in range(G.V())]
self.mst=queue.Queue()
self.visit(G,0)
while len(self.pq)!=0:
e=self.pq[self.getmin(self.pq)]
del self.pq[self.getmin(self.pq)]
v=e.get_either()
w=e.order(v)
if(self.marked[v]==True )and( self.marked[w]==True):
continue
self.mst.put(e)
if self.marked[v]!=True:
self.visit(G,v)
if self.marked[w]!=True:
self.visit(G,w)
def visit(self,G,v):
self.marked[v]=True
for e in G.adj_(v):
if self.marked[e.order(v)]!=True:
self.pq.append(e)
def Edges(self):
return self.mst
def getmin(self,pq): #找到列表pq中的最小元素并返回索引
weitht_=[]
for i in pq:
weitht_.append(i.weight)
s=weitht_.index(min(weitht_))
return s
#测试代码
La=LazyPrimMST(EWG)
while La.Edges().empty()!=True:
print(La.Edges().get().toString())
#输出结果
# 0-1 2.00
# 1-4 7.00
# 4-2 3.00
# 2-3 5.00
```
最小生成树Prim算法的即使实现
```python
class PrimMST:
def __init__(self,G):
self.edgeTo=[Edge(0,0,0)for i in range(G.V())]
self.disTo = [0.00 for i in range(G.V())]
self.marked = [False for i in range(G.V())]
for v in range(G.V()):
self.disTo[v]=float('inf')
self.pq=[]
self.disTo[0]=0.0
self.pq.append((0,0.0))
while len(self.pq)!=0:
s=self.pq[self.getmin(self.pq)][0]
del self.pq[self.getmin(self.pq)]
self.visit(G,s)
def getmin(self, pq): # 找到列表pq中的最小元素并返回索引
weitht_ = []
for i in pq:
weitht_.append(i[1])
s = weitht_.index(min(weitht_))
return s
def visit(self,G,v):
self.marked[v]=True
for e in G.adj_(v):
w=e.order(v)
if self.marked[w]==True:
continue
if e.weight<self.disTo[w]:
self.edgeTo[w]=e
self.disTo[w]=e.weight
if self.con_(self.pq,w):
ss=self.find_(self.pq,w)
self.pq[ss][1]=self.disTo[w]
else:
self.pq.append((w,self.disTo[w]))
def con_(self,pq,w):
site=[]
for p in pq:
site.append(p[0])
return w in site
def find_(self,pq,w):
site=[]
for p in pq:
site.append(p[0])
i=site.index(w)
return i
#测试程序
Pr=PrimMST(EWG)
def get_path(x):
print(Pr.edgeTo[x].toString())
if x!=0:
x=Pr.edgeTo[x].order(x)
get_path(x)
get_path(3)
#输出结果
# 2-3 5.00
# 4-2 3.00
# 1-4 7.00
# 0-1 2.00
# 0-0 0.00
```
kruskal算法,这个的思路是找最短的边先加入表中,形成环的不要,以此类推,找到最小生成树
要用到union_find算法
这个算法要前面的知识,我是跳着读的,现在太晚了,暂时先不研究了
最短路径留在下次吧
2022年2月5日02:39:11
最短路径,精力不足,写得比较简略
```python
#加权有向边
class DirectedEdge:
def __init__(self,v,w,weight):
self.v=v
self.w=w
self.weight=weight
def get_weight(self):
return self.weight
def get_from(self):
return self.v
def get_to(self):
return self.w
def toString(self):
return str.format("%d-%d %.2f"%(self.v,self.w,self.weight))
#加权有向图
class EdgeWeightedDigraph:
def __init__(self,v): #初始化
self.v=v
self.e=0
self.adj=[[]for i in range(v)]
def addEdge(self,e): #添加边
self.adj[e.get_from()].append(e)
self.e=self.e+1
def V(self):
return self.v
def E(self):
return self.e
def adj_(self,v): #获得所有相邻边
return self.adj[v]
def getNumberOfVertex(self):
return self.v
#设置边和加载图
DWedge_1=DirectedEdge(0,1,4)
DWedge_2=DirectedEdge(0,2,5)
DWedge_3=DirectedEdge(1,3,3)
DWedge_4=DirectedEdge(2,3,8)
DWedge_5=DirectedEdge(2,4,5)
DWedge_6=DirectedEdge(3,4,7)
DWedge_7=DirectedEdge(4,5,8)
DWedge_8=DirectedEdge(2,5,2)
EWD=EdgeWeightedDigraph(6)
EWD.addEdge(DWedge_1)
EWD.addEdge(DWedge_2)
EWD.addEdge(DWedge_3)
EWD.addEdge(DWedge_4)
EWD.addEdge(DWedge_5)
EWD.addEdge(DWedge_6)
EWD.addEdge(DWedge_7)
EWD.addEdge(DWedge_8)
#最短路径实现方法1:
#最短路径的Dijkstra算法
class DijkstraSP:
def __init__(self,G,s):
self.edgeTo=[DirectedEdge(0,0,0)for i in range(G.V())]
self.disTo = [0.00 for i in range(G.V())]
for v in range(G.V()):
self.disTo[v]=float('inf')
self.pq=[]
self.disTo[s]=0.0
self.pq.append((s,0.0))
while len(self.pq)!=0:
s=self.pq[self.getmin(self.pq)][0]
del self.pq[self.getmin(self.pq)]
self.relax(G,s)
def getmin(self, pq): # 找到列表pq中的最小元素并返回索引
weitht_ = []
for i in pq:
weitht_.append(i[1])
s = weitht_.index(min(weitht_))
return s
def relax(self,G,v):
for e in G.adj_(v):
w=e.get_to()
if self.disTo[w]>self.disTo[v]+e.weight:
self.disTo[w]=self.disTo[v]+e.weight
self.edgeTo[w]=e
if self.con_(self.pq,w):
self.pq[self.find_(self.pq,w)][1]=self.disTo[w]
else:
self.pq.append((w,self.disTo[w]))
def con_(self,pq,w):
site=[]
for p in pq:
site.append(p[0])
return w in site
def find_(self,pq,w):
site=[]
for p in pq:
site.append(p[0])
i=site.index(w)
return i
def get_path(self,x):
print("dd "+str(self.edgeTo[x].toString()))
if x != 0:
x = self.edgeTo[x].get_from()
self.get_path(x)
def get_distTo(self,v):
return self.disTo[v]
def hasPathTo(self,v):
return self.disTo[v]<float('inf')
DDD=DijkstraSP(EWD,0)
DDD.get_path(4)
#输出结果
# dd 2-4 5.00
# dd 0-2 5.00
# dd 0-0 0.00
#最短路径实现方法2:
#无环加权有向图的最短路径算法
#基于深度优先的顶点排序
class DepthFirstOrder:
def __init__(self,G):
self.pre=queue.Queue()
self.post=queue.Queue()
self.reversePost=deque()
self.marked=[False for i in range(G.getNumberOfVertex())]
for v in range(G.getNumberOfVertex()):
if self.marked[v]!=True:
self.dfs(G,v)
def dfs(self,G,v):
self.pre.put(v)
self.marked[v]=True
for w in G.adj_(v):
if(self.marked[w.get_to()]!=True):
self.dfs(G,w.get_to())
self.post.put(v)
self.reversePost.append(v)
def get_pre(self):
return self.pre
def get_post(self):
return self.post
def get_reversePost(self):
return self.reversePost
#实现方法
class AcyclicSP:
def __init__(self,G,s):
self.edgeTo = [DirectedEdge(0, 0, 0) for i in range(G.V())]
self.disTo = [0.00 for i in range(G.V())]
for v in range(G.V()):
self.disTo[v] = float('inf')
self.disTo[s]=0.0
self.topu=DepthFirstOrder(G)
for v in list(self.topu.get_pre().queue):
self.relax(G,v)
def relax(self, G, v):
for e in G.adj_(v):
w = e.get_to()
if self.disTo[w] > self.disTo[v] + e.weight:
self.disTo[w] = self.disTo[v] + e.weight
self.edgeTo[w] = e
def get_path(self, x):
print("bb " + str(self.edgeTo[x].toString()))
if x != 0:
x = self.edgeTo[x].get_from()
self.get_path(x)
def get_distTo(self, v):
return self.disTo[v]
def hasPathTo(self, v):
return self.disTo[v] < float('inf')
AS=AcyclicSP(EWD,0)
AS.get_path(4)
#输出结果
# bb 2-4 5.00
# bb 0-2 5.00
# bb 0-0 0.00
```
图方法的python实现基本就完成啦!
基于书籍《算法》第四版
还参考了网络上面的各种资料,感谢各位大佬了!