图方法的python实现

本文详细介绍了如何使用Python实现无向图、有向图及其相关算法,包括邻接表表示、深度优先搜索(DFS)、广度优先搜索(BFS)、连通分量、环检测、顶点排序和最小生成树等。通过实例展示了这些算法的代码实现,为理解图论和算法提供了实践基础。
摘要由CSDN通过智能技术生成

本文基于书籍《算法》第四版,并且结合了网络上的代码和解决方案

环境:

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实现基本就完成啦!  

基于书籍《算法》第四版  

还参考了网络上面的各种资料,感谢各位大佬了!  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Beta-Zero

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值