|
楼主 |
发表于 2023-12-30 17:19:41
|
显示全部楼层
from abc import ABCMeta, abstractmethod, abstractproperty
import sys
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
class LinkQueue:
def __init__(self):
self.front = None # 队首指针
self.rear = None # 队尾指针
def clear(self):
'''将队列置空'''
self.front = None
self.rear = None
def isEmpty(self):
'''判断队列是否为空'''
return self.front is None
def length(self):
'''返回队列的数据元素个数'''
p = self.front
i = 0
while p is not None:
p = p.next
i += 1
return i
def peek(self):
'''返回队首元素'''
if self.isEmpty():
return None
else:
return self.front.data
def offer(self, x):
'''将数据元素x插入到队列成为队尾元素'''
s = Node(x, None)
if not self.isEmpty():
self.rear.next = s
else:
self.front = s
self.rear = s
def poll(self):
'''将队首元素删除并返回其值'''
if self.isEmpty():
return None
p = self.front
self.front = self.front.next
if p == self.rear: # 删除结点为队尾结点时需要修改rear
self.rear = None
return p.data
def display(self):
'''输出队列中的所有元素'''
p = self.front
while p is not None:
print(p.data, end=' ')
p = p.next
class IGraph(metaclass=ABCMeta):
@abstractmethod
def createGraph(self):
'''创建图'''
pass
@abstractmethod
def getVNum(self):
'''返回图中的顶点数'''
pass
@abstractmethod
def getENum(self):
'''返回图中的边数'''
pass
@abstractmethod
def getVex(self, i):
'''返回位置为i的顶点值'''
pass
@abstractmethod
def locateVex(self, x):
'''返回值为x的顶点位置'''
pass
@abstractmethod
def firstAdj(self, i):
'''返回结点的第一个邻接点'''
pass
@abstractmethod
def nextAdj(self, i, j):
'''返回相对于j的下一个邻接点'''
pass
class MGraph(IGraph):
# 图类别静态常量
GRAPHKIND_UDG = 'UDG'
GRAPHKIND_DG = 'DG'
GRAPHKIND_UDN = 'UDN'
GRAPHKIND_DN = 'DN'
def __init__(self, kind=None, vNum=0, eNum=0, v=None, e=None):
self.kind = kind # 图的种类
self.vNum = vNum # 图的顶点数
self.eNum = eNum # 图的边数
self.v = v # 顶点列表
self.e = e # 邻接矩阵
def createUDG(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[0] * vNum] * vNum # 构造边集
for i in range(eNum):
a, b = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = self.e[n][m] = 1
def createDG(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[0] * vNum] * vNum # 构造边集
for i in range(eNum):
a, b = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = 1
def createUDN(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[sys.maxsize] * vNum] * vNum # 初始化边集
for i in range(eNum):
a, b, w = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = self.e[n][m] = w
def createDN(self, vNum, eNum, v, e):
self.vNum = vNum
self.eNum = eNum
self.v = [None] * vNum # 构造顶点集
for i in range(vNum):
self.v[i] = v[i]
self.e = [[sys.maxsize] * vNum] * vNum # 初始化边集
for i in range(eNum):
a, b, w = e[i]
m, n = self.locateVex(a), self.locateVex(b)
self.e[m][n] = w
def locateVex(self, x):
for i in range(self.vNum):
if self.v[i] == x:
return i
return -1
def firstAdj(self, i):
if i < 0 or i >= self.vNum:
raise Exception("第%s个顶点不存在" % i)
for j in range(self.vNum):
if self.e[i][j] != 0 and self.e[i][j] < sys.maxsize:
return j
return -1
def nextAdj(self, i, j):
if j == self.vNum - 1:
return -1
for k in range(j + 1, self.vNum):
if self.e[i][k] != 0 and self.e[i][k] < sys.maxsize:
return k
return -1
class VNode(object):
def __init__(self, data=None, firstNode=None):
self.data = data # 存放结点值
self.firstArc = firstNode # 第一条边
class ArcNode(object):
def __init__(self, adjVex, value, nextArc=None):
self.adjVex = adjVex # 边指向的顶点的位置
self.value = value # 边的权值
self.nextArc = nextArc # 指向下一条边
class ALGraph(IGraph):
# 图类别静态常量
GRAPHKIND_UDG = 'UDG'
GRAPHKIND_DG = 'DG'
GRAPHKIND_UDN = 'UDN'
GRAPHKIND_DN = 'DN'
def __init__(self, kind=None, vNum=0, eNum=0, v=None, e=None):
self.kind = kind # 图的种类
self.vNum = vNum # 图的顶点数
self.eNum = eNum # 图的边数
self.v = v # 顶点列表
self.e = e # 边信息
def createGraph(self):
if self.kind == self.GRAPHKIND_UDG:
self.createUDG()
elif self.kind == self.GRAPHKIND_DG:
self.createDG()
elif self.kind == self.GRAPHKIND_UDN:
self.createUDN()
elif self.kind == self.GRAPHKIND_DN:
self.createDN()
def createUDG(self):
'''创建无向图'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, 1)
self.addArc(v, u, 1)
def createDG(self):
'''创建有向图'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, 1)
def createUDN(self):
'''创建无向网'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b, w = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, w)
self.addArc(v, u, w)
def createDN(self):
'''创建有向网'''
v = self.v
self.v = [None] * self.vNum
for i in range(self.vNum):
self.v[i] = VNode(v[i])
for i in range(self.eNum):
a, b, w = self.e[i]
u, v = self.locateVex(a), self.locateVex(b)
self.addArc(u, v, w)
def addArc(self, i, j, value):
'''插入边结点'''
arc = ArcNode(j, value)
arc.nextArc = self.v[i].firstArc
self.v[i].firstArc = arc
def firstAdj(self, i):
'''查找第一个邻接点'''
if i < 0 or i >= self.vNum:
raise Exception("第%s个结点不存在" % i)
p = self.v[i].firstArc
if p is not None:
return p.adjVex
return -1
def nextAdj(self, i, j):
'''返回i相对于j的下一个邻接点'''
if i < 0 or i >= self.vNum:
raise Exception("第%s个结点不存在" % i)
p = self.v[i].firstArc
while p is not None:
if p.adjVex == j:
break
p = p.nextArc
if p.nextArc is not None:
return p.nextArc.adjVex
return -1
def getVNum(self):
'''返回顶点数'''
return self.vNum
def getENum(self):
'''返回边数'''
return self.eNum
def getVex(self, i):
'''返回第i个顶点的值'''
if i < 0 or i >= self.vNum:
raise Exception("第%s个顶点不存在" % i)
return self.v[i].data
def locateVex(self, x):
'''返回值为x的顶点的位置'''
for i in range(self.vNum):
if self.v[i].data == x:
return i
return -1
def getArcs(self, u, v):
'''返回顶点u到顶点v的距离'''
if u < 0 or u >= self.vNum:
raise Exception("第%s个结点不存在" % u)
if v < 0 or v >= self.vNum:
raise Exception("第%s个结点不存在" % v)
p = self.v[u].firstArc
while p is not None:
if p.adjVex == v:
return p.value
p = p.nextArc
return sys.maxsize
#######################################
def BFSTraverse(g):
global visited
# 建立访问标志数组
visited = [False] * g.getVNum()
count = 0
# 以每个顶点作为起始顶点进行遍历
for i in range(g.getVNum()):
if not visited[i]:
count += 1
print(f'第{count}个连通块:', end=' ')
BFS(g, i)
print()
def BFS(g, i):
# 建立辅助队列
q = LinkQueue()
# 将起点加入队列
q.offer(i)
while not q.isEmpty():
u = q.poll()
# 标记顶点已访问
visited[u] = True
print(g.getVex(u), end=' ')
v = g.firstAdj(u)
while v != -1:
# 顶点未访问的邻接点入队
if not visited[v]:
q.offer(v)
# 获取下一个邻接点
v = g.nextAdj(u, v)
########################################
v = [1, 2, 3, 4, 5, 6]
e = [(1, 2), (2, 3), (4, 5)]
g = ALGraph(ALGraph.GRAPHKIND_UDG, len(v), len(e), v, e) # 引用类的属性
g.createGraph()
BFSTraverse(g)
##############################################################
def DFSTraverse(g):
global visited
# 建立访问标志数组
visited = [False] * g.getVNum()
# 以每个顶点作为起始顶点进行遍历
for i in range(g.getVNum()):
if not visited[i]:
DFS(g, i)
def DFS(g, i):
visited[i] = True
print(g.getVex(i), end=' ')
v = g.firstAdj(i)
while v > 0:
if not visited[v]:
DFS(g, v)
v = g.nextAdj(i, v)
class CloseEdge(object):
def __init__(self, adjVex, lowCost):
self.adjVex = adjVex # 在结合U中的顶点的值
self.lowCost = lowCost # 到集合U的最小距离
class MiniSpanTree(object):
def PRIM(g, u):
'''从值为u的顶点出发构造最小生成树,返回由生成树边组成的二维数组'''
tree = [[None, None] for i in range(g.getVNum() - 1)]
count = 0
closeEdge = [None] * g.getVNum()
k = g.locateVex(u)
for j in range(g.getVNum()):
if k != j:
closeEdge[j] = CloseEdge(u, g.getArcs(k, j))
closeEdge[k] = CloseEdge(u, 0)
for i in range(1, g.getVNum()):
k = MiniSpanTree.getMinMum(closeEdge)
tree[count][0] = closeEdge[k].adjVex
tree[count][1] = g.getVex(k)
count += 1
closeEdge[k].lowCost = 0
for j in range(g.getVNum()):
if g.getArcs(k, j) < closeEdge[j].lowCost:
closeEdge[j] = CloseEdge(g.getVex(k), g.getArcs(k, j))
return tree
def getMinMum(closeEdge):
minvalue = sys.maxsize
v = -1
for i in range(len(closeEdge)):
if closeEdge[i].lowCost != 0 and closeEdge[i].lowCost < minvalue:
minvalue = closeEdge[i].lowCost
v = i
return v
class ShortestPath:
def Djikstra(g, v0):
# 存放最短路径,p[v][k]表示从v0到v的最短路径中经过的第k个点
p = [([-1] * g.getVNum()) for i in range(g.getVNum())]
# 存放最短路径长度
D = [sys.maxsize] * g.getVNum()
# 若已找到最短路径,finish[v]为True
finish = [False] * g.getVNum()
v0 = g.locateVex(v0)
for v in range(g.getVNum()):
D[v] = g.getArcs(v0, v)
if D[v] < sys.maxsize:
# 从起点直接可以到达
p[v][0] = v0
p[v][1] = v
p[v0][0] = v0 # 起点本身可以直接到达
D[v0] = 0
finish[v0] = True
v = -1
for i in range(1, g.getVNum()):
minvalue = sys.maxsize
for w in range(g.getVNum()):
# 找出所有最短路径中的最小值
if not finish[w]:
if D[w] < minvalue:
v = w
minvalue = D[w]
finish[v] = True
# 更新当前的最短路径
for w in range(g.getVNum()):
if not finish[w] and g.getArcs(v, w) < sys.maxsize and (minvalue + g.getArcs(v, w) < D[w]):
D[w] = minvalue + g.getArcs(v, w)
for k in range(g.getVNum()):
p[w][k] = p[v][k]
if p[w][k] == -1:
p[w][k] = w
break
dis = {g.getVex(i): D[i] for i in range(g.getVNum())}
# 返回到各点最短路的字典与路径矩阵
return dis, p
def printDjikstraPath(g, v0, p):
# v0到各点的输出最短路径,即p[v][0]到p[v][j]直到p[v][j]==-1
u = v0
v0 = g.locateVex(v0)
for i in range(g.getVNum()):
v = g.getVex(i)
print('%s->%s的最短路径为:' % (u, v), end=' ')
if p[i][0] != -1:
print(g.getVex(p[v0][0]), end='')
for k in range(1, g.getVNum()):
if p[i][k] == -1:
break
print('->%s' % g.getVex(p[i][k]), end='')
print(',长度为:%s' % dis[v])
def Floyd(g): # 多源点最短路径
vNum = g.getVNum()
D = [[sys.maxsize] * vNum for i in range(vNum)]
p = [[-1] * vNum for i in range(vNum)]
for u in range(vNum):
for v in range(vNum):
D[u][v] = g.getArcs(u, v) if u != v else 0
if D[u][v] < sys.maxsize:
p[u][v] = u
for k in range(vNum):
for i in range(vNum):
for j in range(vNum):
if D[i][j] > D[i][k] + D[k][j]:
D[i][j] = D[i][k] + D[k][j]
p[i][k] = i
p[i][j] = p[k][j]
dis = {(g.getVex(u), g.getVex(v)): D[u][v] for u in range(vNum) for v in range(vNum)}
return dis, p
def printFloydPath(g, p):
vNum = g.getVNum()
for u in range(vNum):
for v in range(vNum):
if u == v:
print('%s->%s的最短路径为: %s' % (g.getVex(u), g.getVex(v), g.getVex(u)))
continue
flag = True
path = [v]
t = p[u][path[0]]
while t != u:
if t == -1:
flag = False
break
path = [t] + path
t = p[u][t]
print('%s->%s的最短路径为:' % (g.getVex(u), g.getVex(v)), end=' ')
if flag:
print(g.getVex(u), end='')
for node in path:
print('->%s' % g.getVex(node), end='')
print()
v = [1, 2, 3, 4, 5, 6]
e = [(1, 2, 45), (1, 3, 15), (1, 5, 15),
(3, 1, 10), (2, 4, 20), (2, 5, 15),
(2, 6, 15), (3, 2, 10), (3, 4, 60),
(4, 2, 30), (4, 6, 20)]
g = ALGraph(ALGraph.GRAPHKIND_UDN, len(v), len(e), v, e)
g.createGraph()
dis, p = ShortestPath.Djikstra(g, 1)
ShortestPath.printDjikstraPath(g, 1, p)
def findInDegree(g):
indegree = [0] * g.getVNum()
# 计算每个点的入度
for u in range(g.getVNum()):
v = g.firstAdj(u)
while v != -1:
indegree[v] += 1
v = g.nextAdj(u, v)
return indegree
def topoSort(g):
count = 0
indegree = findInDegree(g)
s = LinkStack()
topo = []
for i in range(g.getVNum()):
# 入度为0的点入栈
if indegree[i] == 0:
s.push(i)
while not s.isEmpty():
u = s.pop()
topo.append(u)
count += 1
# 对该点的每个邻接点的入度-1
v = g.firstAdj(u)
while v != -1:
indegree[v] -= 1
if indegree[v] == 0:
s.push(v)
v = g.nextAdj(u, v)
if count < g.getVNum():
return None
return [g.getVex(u) for u in topo]
def topoOrder(g):
count = 0
indegree = findInDegree(g)
s = LinkStack()
t = LinkStack() # 记录拓扑顺序
ve = [0] * g.getVNum()
for i in range(g.getVNum()):
# 入度为0的点入栈
if indegree[i] == 0:
s.push(i)
while not s.isEmpty():
u = s.pop()
t.push(u)
count += 1
# 对该点的每个邻接点的入度-1
v = g.firstAdj(u)
while v != -1:
indegree[v] -= 1
if indegree[v] == 0:
s.push(v)
# 更新最早发生时间
if ve[u] + g.getArcs(u, v) > ve[v]:
ve[v] = ve[u] + g.getArcs(u, v)
v = g.nextAdj(u, v)
if count < g.getVNum():
return None, None
return ve, t
def criticalPath(g):
ve, t = topoOrder(g)
if ve is None:
return None
vl = [ve[t.top.data]] * g.getVNum()
# 逆拓扑序求各顶点的vl值
while not t.isEmpty():
u = t.pop()
v = g.firstAdj(u)
while v != -1:
if vl[v] - g.getArcs(u, v) < vl[u]:
vl[u] = vl[v] - g.getArcs(u, v)
v = g.nextAdj(u, v)
# 输出关键活动
print("关键活动为:", end='')
for i in range(g.getVNum()):
if ve[i] == vl[i]:
print(g.getVex(i), end=' ')
print()
# 6.6
v = ['A', 'B', 'C', 'D', 'E', 'F']
e = [
('A', 'B', 7), ('A', 'C', 5), ('A', 'D', 1),
('B', 'D', 6), ('B', 'E', 3), ('C', 'D', 7),
('C', 'F', 2), ('D', 'E', 6), ('D', 'F', 4),
('E', 'F', 7)
]
g1 = ALGraph(ALGraph.GRAPHKIND_UDN, len(v), len(e), v, e)
g1.createGraph()
print(MiniSpanTree.PRIM(g1, 'A'))
将你使用的BFS替换为我这里的用法 |
|