adj_matrix.py
"""
邻接矩阵
:class VertexNode: 顶点结点类
:class ArcNode: 弧结点类
:class AdjMatrix: 邻接矩阵类
:method create_adj_matrix: 创建一个邻接矩阵对象
:method depth_first_search_recursion: 深度优先递归遍历
:method depth_first_search_nonrecursion: 深度优先非递归遍历
:method breadth_first_search_nonrecursion: 广度优先非递归遍历
:class TravVistor: 访问者类,对深度优先递归、深度优先非递归、广度优先非递归的访问
:method travers_graph: 遍历接口,设置不同参数利用TravVistor对象实现深度优先递归、深度优先非递归、广度优先非递归调用
:method mini_span_tree_prim: 最小生成树,普利姆算法
:method mini_span_tree_kruskal: 最小生成树,克鲁斯卡尔算法
:method topo_sort: 拓扑排序
:method shortest_path_djs: 迪杰斯特拉算法,计算从某一顶点开始到其余顶点的最短路径
:method shortest_path_floyd: 弗洛伊德算法,计算任意两个顶点之间的最短路径
:method center_vex: 计算中心结点
"""
import numpy as np
from typing import List, Tuple, Union
from collections import deque
from array import array
graph_kind_ = {"DG": 0, "DN": 32768, "UDG": 0, "UDN": 32768}
class VertexNode:
def __init__(self, name: str):
self.name = name
self.other_info = None
class ArcNode:
def __init__(self, arc_tail: VertexNode, arc_head: VertexNode, weight: Union[int, float]):
self.arc_head = arc_head
self.arc_tail = arc_tail
self.weight = weight
self.other_info = None
class AdjMatrix:
def __init__(self):
self.vertexs: List = []
self.vex_num: int = 0
self.arc_num: int = 0
self.arcs_matrix: np = None
self.graph_kind: str = ""
def locate_vertex(adj_matrix: AdjMatrix, vertex_node: VertexNode):
"""
获取顶点的位置
:param adj_matrix: 在该邻接矩阵对象的顶点列表中查找顶点结点位置
:param vertex_node: 所需查找位置的顶点结点
:return: 顶点结点的索引
"""
for index, vertex_node_item in enumerate(adj_matrix.vertexs):
if vertex_node.name == vertex_node_item.name:
return index
def create_adj_matrix(adj_matrix: AdjMatrix, vertexs: List[VertexNode],
arcs: List[Union[Tuple[VertexNode, VertexNode, int], Tuple[VertexNode, VertexNode, float]]],
graph_kind: str = 'DN'):
"""
创建一个邻接矩阵
:param adj_matrix: 一个空的邻接矩阵
:param vertexs: 顶点列表
:param arcs: 弧列表
:param graph_kind: 所创建的图的种类:DG表示有向图,DN表示有向网,UDG表示无向图,UDN表示无向图
:return: None
"""
adj_matrix.vertexs = vertexs
adj_matrix.arc_num = len(arcs)
adj_matrix.vex_num = len(adj_matrix.vertexs)
adj_matrix.graph_kind = graph_kind
adj_matrix.arcs_matrix = np.ones([adj_matrix.vex_num, adj_matrix.vex_num]) * graph_kind_[graph_kind]
for arc in arcs:
arc_node = ArcNode(*arc)
i = locate_vertex(adj_matrix, arc_node.arc_tail)
j = locate_vertex(adj_matrix, arc_node.arc_head)
if graph_kind == "DN" or graph_kind == "DG":
adj_matrix.arcs_matrix[i][j] = arc_node.weight
else:
adj_matrix.arcs_matrix[i][j] = arc_node.weight
adj_matrix.arcs_matrix[j][i] = arc_node.weight
if graph_kind == 'DN' or graph_kind == 'UDN':
for i in range(adj_matrix.vex_num):
adj_matrix.arcs_matrix[i][i] = 0
visited = array('i', [])
trav_seq = deque()
def depth_first_search_recursion(adj_matrix: AdjMatrix, vertex_node: VertexNode):
"""
深度遍历图
算法思想:
(1) 访问出发点v0;
(2) 依次以v0的未被访问的临界点为出发点,深度优先搜索图,直至图中所有与v0有路径相通的顶点都被访问。
:param adj_matrix: 已创建好的邻接矩阵对象
:param vertex_node: 访问出发点v0
:return: 深度遍历序列
"""
vi_index = locate_vertex(adj_matrix, vertex_node)
trav_seq.append(adj_matrix.vertexs[vi_index])
visited[vi_index] = 1
for vj_index in range(adj_matrix.vex_num):
if not visited[vj_index] and 0 < adj_matrix.arcs_matrix[vi_index][vj_index] <= graph_kind_['DN']:
depth_first_search_recursion(adj_matrix, adj_matrix.vertexs[vj_index])
return trav_seq
def depth_first_search_nonrecursion(adj_matrix: AdjMatrix, vertex_node: VertexNode):
"""
深度非递归遍历图
算法思想:
(1) 首先将v0入栈
(2) 只要栈不空,则重复下述处理:栈顶顶点出栈,如果未访问,则访问并置访问标志;然后将该顶点所有未访问的邻接点入栈。
:param adj_matrix: 已创建好的邻接矩阵对象
:param vertex_node: 访问出发点v0
:return: 深度遍历序列
"""
temp_stack = deque()
temp_stack.append(vertex_node)
while temp_stack:
vi_node = temp_stack.pop()
vi_index = locate_vertex(adj_matrix, vi_node)
if not visited[vi_index]:
trav_seq.append(vi_node)
visited[vi_index] = 1
for vj_index in range(adj_matrix.vex_num):
if not visited[vj_index] and 0 < adj_matrix.arcs_matrix[vi_index][vj_index] <= graph_kind_["DN"]:
temp_stack.append(adj_matrix.vertexs[vj_index])
return trav_seq
def breadth_first_search_nonrecursion(adj_matrix: AdjMatrix, vertex_node: VertexNode):
temp_queue = deque()
temp_queue.append(vertex_node)
while temp_queue:
vi_node = temp_queue.popleft()
vi_index = locate_vertex(adj_matrix, vi_node)
if not visited[vi_index]:
trav_seq.append(vi_node)
visited[vi_index] = 1
for vj_index in range(adj_matrix.vex_num):
if not visited[vj_index] and 0 < adj_matrix.arcs_matrix[vi_index][vj_index] <= graph_kind_["DN"]:
temp_queue.append(adj_matrix.vertexs[vj_index])
return trav_seq
class TravVistor:
"""
遍历访问者
访问者设计模式:使用同一个方法对不同对象访问具有不同的行为
对不同的遍历方法使用同一个方法traver_graph进行遍历
"""
__recursion_nonrecursion = {"r": "recursion", "nr": "nonrecursion"}
__depth_breadth = {"d": "depth", "b": "breadth"}
def __init__(self, adj_list, vertex_node, depth_breadth: str, recursion_nonrecursion: str):
self.adj_list = adj_list
self.vertex_node = vertex_node
self.depth_breadth = depth_breadth
self.recursion_nonrecursion = recursion_nonrecursion
def traver_graph(self):
func_name = f'{self.__depth_breadth[self.depth_breadth]}_first_search_{self.__recursion_nonrecursion[self.recursion_nonrecursion]}'
func_obj = getattr(self, func_name, None)
return func_obj()
def depth_first_search_recursion(self):
return depth_first_search_recursion(self.adj_list, self.vertex_node)
def depth_first_search_nonrecursion(self):
return depth_first_search_nonrecursion(self.adj_list, self.vertex_node)
def breadth_first_search_nonrecursion(self):
return breadth_first_search_nonrecursion(self.adj_list, self.vertex_node)
def travers_graph(adj_matrix: AdjMatrix, deepth_breadth: str = "d", recursion_nonrecursion: str = "nr"):
"""
遍历图
算法思想:
若是非连通图,则途中一定还有顶点未被访问,需要从途中另选一个未被访问过的顶点作为起始顶点,重复深度优先搜索过程,
直至图中所有的顶点均被访问过为止。
:param adj_list: 已创建好的邻接表对象
:param deepth_breadth: 选用深度deepth_breadth = 'd', 选用广度deepth_breadth = 'b'
:param recursion_nonrecursion: 选用递归way = 'r' ,选用非递归way = 'nr'
:return: 返回多个连通子图的遍历序列
"""
travers_list = deque()
for vi_index in range(adj_matrix.vex_num):
visited.append(0)
for vi_index in range(adj_matrix.vex_num):
if not visited[vi_index]:
trav_vistor = TravVistor(adj_matrix, adj_matrix.vertexs[vi_index], deepth_breadth,
recursion_nonrecursion)
travers_list.append(trav_vistor.traver_graph().copy())
trav_seq.clear()
return travers_list
def min_(closedage) -> int:
temp_weight = 32768
temp_index = 0
for i in range(0, len(closedage)):
if closedage[i][1] != 0 and temp_weight > closedage[i][1]:
temp_weight = closedage[i][1]
temp_index = i
return temp_index
def mini_span_tree_prim(adj_matrix: AdjMatrix, vertex_start: VertexNode):
"""
最小生成树:普利姆算法:加点法,适用于稠密网
算法思想:
(1) 首先将初始顶点vertex_start加入到U中,对其余的每一个顶点i,将closedge[i]初始化为i到vertex_start边信息;
(2) 循环n-1次,做如下处理:
a. 从各组最小边closedge[v]中选出最小的最小边closedge[k](v,k属于V-U)
b. 将k加入到U中
c. 更新剩余的每组最小边信息closedge[v](v属于V-U)
#closedge[v] = List[List[adjvex, lowcost]]
a. adjvex 记录最小边在U中的那个顶点
b. lowcost 存储最小边的权值
算法时间复杂度:
由于算法中有两个for循环嵌套,故它的时间复杂度为O(n**2)
:param adj_matrix:
:param vertex_start:
:return:
"""
vk_index = locate_vertex(adj_matrix, vertex_start)
vex_num = adj_matrix.vex_num
closedage = []
edges = deque()
for i in range(vex_num):
if i == vk_index:
closedage.append([adj_matrix.vertexs[vk_index], 0])
else:
closedage.append([adj_matrix.vertexs[vk_index], adj_matrix.arcs_matrix[vk_index][i]])
for i in range(1, vex_num):
k = min_(closedage)
arc_tail = closedage[k][0]
arc_head = adj_matrix.vertexs[k]
edges.append((arc_tail, arc_head, closedage[k][1]))
closedage[k][1] = 0
for j in range(vex_num):
if adj_matrix.arcs_matrix[k][j] < closedage[j][1]:
closedage[j][1] = adj_matrix.arcs_matrix[k][j]
closedage[j][0] = arc_head
return edges
def adj_matrix_arcs(adj_matrix: AdjMatrix):
arcs = []
if adj_matrix.graph_kind == "UDG" or adj_matrix.graph_kind =="DG":
for i in range(adj_matrix.vex_num):
for j in range(adj_matrix.vex_num):
if adj_matrix.arcs_matrix[i][j] == 1:
arcs.append((adj_matrix.vertexs[i], adj_matrix.vertexs[j], 1))
else:
for i in range(adj_matrix.vex_num):
for j in range(adj_matrix.vex_num):
if adj_matrix.arcs_matrix[i][j] < 32768:
arcs.append((adj_matrix.vertexs[i], adj_matrix.vertexs[j], adj_matrix.arcs_matrix[i][j]))
return arcs
def mini_span_tree_kruskal(adj_matrix: AdjMatrix):
"""
最小生成树:克鲁斯卡尔算法:加边发,适合于稀疏网
算法思想:
假设N = (V, {#})是联通图,将N中的边按边权值从小到大的顺序排列。
(1) 将n个顶点看成n个集合。
(2) 按权值由小到大的顺序选择边,所选边应满足两个顶点不在同一个顶点集合内,将改变放到生成树边的集合中,同时将该边的
两个顶尖所在的顶点集合合并
(3) 重复(2)直到所有的顶点都在同一个顶点集合内
算法时间复杂度:
克鲁斯卡尔算法的时间复杂度主要由排序方法决定,而克鲁斯卡尔算法的排序方法只与网中边的条数有关,而与网中顶点的个数无
关,当使用时间复杂度为O(elog2e)的排序方法时,克鲁斯卡尔算法的时间复杂度即为O(log2e),因此当网的顶点个数较多、
而边的条数较少时,使用克鲁斯卡尔算法构造最小生成树效果较好
:param adj_matrix: 邻接矩阵
:return: 最小生成树的边序列
"""
awaited_edges = adj_matrix_arcs(adj_matrix)
vex_index_dict = {}
for index, vertex_node in enumerate(adj_matrix.vertexs):
vex_index_dict.setdefault(vertex_node, index)
from mf_set import MFSet, SeqList
vex_set = MFSet()
vex_set.initialization(SeqList([i for i in range(index+1)]))
tree_edges = deque()
abc = lambda edge: edge[2]
awaited_edges = sorted(awaited_edges, key=abc, reverse=True)
while awaited_edges:
edge_min = awaited_edges.pop()
i = vex_set.find_2(vex_index_dict[edge_min[0]])
j = vex_set.find_2(vex_index_dict[edge_min[1]])
if i == j:
continue
tree_edges.append(edge_min)
vex_set.merge(i, j)
return tree_edges
def find_id(adj_matrix: AdjMatrix, indegree: array):
for i in range(adj_matrix.vex_num):
indegree.append(0)
for arc_head_index in range(adj_matrix.vex_num):
for arc_tail_index in range(adj_matrix.vex_num):
if adj_matrix.arcs_matrix[arc_tail_index][arc_head_index] == 1:
indegree[arc_head_index] += 1
return indegree
def topo_sort(adj_matrix: AdjMatrix):
"""
拓扑排序:邻接矩阵
拓扑排序:
在有向图G=(V, {E})中,V中顶点的线性序列(vi1,vi2,vi3,...,vin)称为拓扑序列。如果此序列满足条件:对序列中任意两个顶点
vi,vj,在G中有一条从vi到vj的路径,则在序列中vi必排在vj之前。
拓扑排序基本思想:
(1) 从有向图中选一个无前驱的结点输出;
(2) 将此结点和以它为起点的边删除
(3) 重复(1)(2),直到不存下来无前驱的结点
(4) 若此时输出的结点数小于有向图的顶点数,则说明有向图中存在回路,否则输出的顶点顺序即为一个拓扑序列
基于邻接矩阵的存储结构:
此时入度为0的顶点即没有前驱的顶点,因此可以附设一个存放各顶点入度的数组indegree[],于是有:
(1) 找G中无前驱的顶点--查找indegree[i]为零的顶点i;
(2) 删除以i为起点的所有弧--对链在顶点i后面的所有临界顶点k,将对应的indegree[k]减1
为了避免重复检测入读为0的顶点,可以再设置一个辅助栈,若某一顶点的入度减为0,则将它入栈,每当输出
某一顶点时,便将它从栈种删除。
算法思想:
(1) 首先求出各顶点的入度,并将入度为0的顶点入栈。
(2) 只要栈不空,则重复下面处理:
a. 将栈顶顶点i出栈并打印
b. 将栈顶顶点i的每一个邻接点k的入度减1,如果顶点k的入度变为0,则将顶点k入栈。
算法时间复杂度:
若有向无环图有n个顶点和e条弧,则在拓扑排序的算法中,for循环需要执行n次,时间复杂度为O(n);对于while循
环,由于每一顶点必定出栈一次,出一次栈,其时间复杂度为O(n),每次都有一个n列的循环;故该算法的时间复杂
度为O(n+n**2),即O(n**2)
:param adj_matrix: 需要拓扑排序的邻接矩阵
:return: 拓扑排序序列
"""
indegree = array('i', [])
temp_stack = deque()
vex_seq = deque()
counter = 0
indegree = find_id(adj_matrix, indegree)
for index, value in enumerate(indegree):
if value == 0:
temp_stack.append((adj_matrix.vertexs[index], index))
indegree[index] -= 1
while temp_stack:
vertex_node_index = temp_stack.pop()
vex_seq.append(vertex_node_index[0])
counter += 1
arc_tail_index = vertex_node_index[1]
for arc_head_index in range(adj_matrix.vex_num):
if adj_matrix.arcs_matrix[arc_tail_index][arc_head_index] == 1:
indegree[arc_head_index] -= 1
if indegree[arc_head_index] == 0:
temp_stack.append((adj_matrix.vertexs[arc_head_index], arc_head_index))
indegree[arc_head_index] -= 1
if counter < adj_matrix.vex_num:
return "ERROR"
return vex_seq
def min__(dist) -> int:
min_value = graph_kind_['DN']
min_p = None
for index, value in enumerate(dist):
if value and min_value > value:
min_value = value
min_p = index
print(min_p, )
return min_p
def shortest_path_djs(adj_matrix: AdjMatrix, vertex_node: VertexNode):
"""
迪杰斯特拉算法:邻接矩阵
最短路径:求一个顶点到其他各顶点的最短路径
算法中使用了辅助数组dist[],dist[i]表示目前已经找到的、从开始点v0到终点vi的当面最短路径的长度。它的初值为:如
果v0到vi有弧,则dist[i]为弧的权值;否则dist[i]为 ∞。
长度最短的一条最短路径必为(v0,vk),vk满足如下条件:
dist[k] = Min{dist[i]|vi∈V-S}
求得顶点vk的最后路径后,将vk加入到第一组顶点集S中。
每加入一个新的顶点vk到顶点集S中,对第二组剩余的各个顶点而言,就多了一个"中转"结点,从而多了一个"中转"路径,所
以要对第二组剩余的各个顶点的最短路径长度dist[i]进行修正。
原来v0到vi的最短路径长度为dist[i],加紧vk后,已vk作为中间顶点的"中转"路径长度为dist[k]+wki,(wki为弧<vk, vi>上
的权值),若“中转”路径长度小于dist[i],则将顶点vi的最短路径长度修正为“中转”路径长度。
修正后,在选择数组dist[]中最小的顶点加入到第一组顶点集S中,如此进行下去,直到图中所有顶点都加入到第一组顶点集S
中为止。
另外,为了记录从v0出发到其余各点的最短路径(顶点序列),引进辅助数组paths[],path[i]表示目前已经找到的、从开始点
v0到终点vi的当前最短路径顶点序列。它的初值为:如果从v0到vi有弧,则path[i]为(v0,vi);否则path[i]为空。
算法思想:
(1) S←{v0};
dist[i] = g.arcs[v0][vi].adj(vi∈V-S)
(将v0到其余顶点的最短路径长度初始化为权值)
(2) 选择vk,使得dist[k] = Min(dist[i]|vi∈V-S),vk为目前求得的下一条从v0出发的最短路径的终点;
(3) 将vk加入S;
(4) 修正从v0出发到集合V-S上任一顶点vi的最短路径的长度;
从vo出发到集合V-S上任一顶点vi的当前最短路径的长度为dist[i],
从v0出发,中间经过新加入S的vk,然后到达集合V-S上任一顶点vi的路径长度为:
dist[k]+g.arcs[k][i].adj
如果dist[k] + g.arcs[k][i].adj < dist[i],则dist[i]=dist[k] + g.arcs[k][i].adj。
(5) 重复(2)-(4)共n-1次,即可按最短路径长度的递增循序,主格求出v0到途中其他每个顶点的最短路径。
算法时间复杂度:
算法前半部分完成了对向量最短路径长度dist[]、路径path[]及顶点集S的初始化工作。
算法后半部分通过n-1次循环,将第二组顶点集V-S中的顶点按照递增有序方式加入到集合S中,并求得从顶
点v0出发到达图中其余顶点的最短路径。
显然,算法的时间复杂度为O(n**2)
:param adj_matrix: 创建好的邻接矩阵对象,即图g
:param vertex_node: 起始顶点
:return: paths, paths_weight
"""
paths = deque()
paths_weight = deque()
dist = deque()
for i in range(adj_matrix.vex_num):
paths.append(deque())
paths_weight.append(None)
dist.append(0)
vertex_index = locate_vertex(adj_matrix, vertex_node)
for i in range(adj_matrix.vex_num):
if vertex_index == i:
dist[i] = None
paths[i].append(adj_matrix.vertexs[i])
paths_weight[i] = 0
else:
dist[i] = adj_matrix.arcs_matrix[vertex_index][i]
if adj_matrix.arcs_matrix[vertex_index][i] < graph_kind_['DN']:
paths[i].append(adj_matrix.vertexs[vertex_index])
paths[i].append(adj_matrix.vertexs[i])
for i in range(adj_matrix.vex_num):
arc_tail_index = min__(dist)
if not arc_tail_index:
return paths, paths_weight
for arc_head_index in range(adj_matrix.vex_num):
if dist[arc_head_index] and adj_matrix.arcs_matrix[arc_tail_index][arc_head_index] < graph_kind_['DN'] \
and dist[arc_tail_index] + adj_matrix.arcs_matrix[arc_tail_index][arc_head_index] < \
dist[arc_head_index]:
dist[arc_head_index] = dist[arc_tail_index] + adj_matrix.arcs_matrix[arc_tail_index][arc_head_index]
paths[arc_head_index] = paths[arc_tail_index].copy()
paths[arc_head_index].append(adj_matrix.vertexs[arc_head_index])
paths_weight[arc_tail_index] = dist[arc_tail_index]
dist[arc_tail_index] = None
def shortest_path_floyd(adj_matrix: AdjMatrix):
"""
求任一对顶点间的最短路径:弗洛伊德算法:邻接矩阵
算法思想:
设g用邻接矩阵表示,求图g中任意对顶点vi与vj间的最短路径(以下序号是D,P两个矩阵的下表)
(-1)将vi到vj的最短的路径长度初始化为g.arcs[i][j].adj,然后进行如下n次比较和修正:
(0) 在vi与vj间加入顶点v0,得到(vi,v0,vj)和(vi,vj)的路径长度,取其中较短的路径作为vi到vj的且中间顶点号
不大于0的最短路径。
(1) 在vi与vj间加入顶点v1,得到(vi,...,v1)和(v1,...,vj),其中(vi,...,v1)是vi到v1的且中间顶点号不大于0的最
短路径,(v1,...,v1,...,vj)与上一步已求出的且vi到vj中间顶点号不大于0的最短路径比较,取其中较短的路径
作为vi到vj的且中间顶点号不大于1的最短路径
(2) 在vi与vj间加入顶点v2,得(vi,...,v2)和(v2,...,vj),其中(vi,...,v2)是vi到v2的且中间顶点号不大于1的最
短路径,(v2,...,vj)是v2到vj的且中间顶点号不大于1的最短路径,这两条路径在上一步中已求出。将(vi,...,v2,
...,vj)与上一步已求出的且vi到vj中间顶点号不大于1的最短路径比较,取其中较短的路径作为vi到vj的且中间顶
点号不大于2的最短路径。
..........
以此类推,经过n次比较和修正,在第n-1步,将求得vi到vj的且中间顶点号不大于n-1的最短路径,这必是从vi到vj
的最短路径。
图g中所有顶点偶对vi与vj间的最短路径长短对应一个n阶方阵D。在上述N+1步中,D的值不断变化,对应一个n阶方
阵序列。
算法时间复杂度:
O(n**3)
:param adj_matrix: 已创建好的邻接矩阵
:return: 返回各路径与路径长度信息
"""
paths = deque()
dist = adj_matrix.arcs_matrix.copy()
for i in range(adj_matrix.vex_num):
paths.append(deque())
for j in range(adj_matrix.vex_num):
paths[i].append(deque())
if adj_matrix.arcs_matrix[i][j] < graph_kind_['DN'] and adj_matrix.arcs_matrix[i][j] != 0:
paths[i][j].append(adj_matrix.vertexs[i])
paths[i][j].append(adj_matrix.vertexs[j])
for k in range(adj_matrix.vex_num):
for i in range(adj_matrix.vex_num):
for j in range(adj_matrix.vex_num):
if k == i or k == j or i == j:
continue
weight_i_k_j = dist[i][k] + dist[k][j]
if weight_i_k_j < dist[i][j]:
dist[i][j] = weight_i_k_j
temp_path = paths[i][k].copy()
temp_path.pop()
temp_path.extend(paths[k][j].copy())
paths[i][j] = temp_path
return paths, dist
def center_vex(adj_list: AdjMatrix):
paths, path_weight = shortest_path_floyd(adj_list)
temp_row_index = 0
temp_row_sum = graph_kind_['DN']*adj_list.vex_num
path_row_sum = 0
for row in range(adj_list.vex_num):
for col in range(adj_list.vex_num):
path_row_sum += path_weight[row][col]
if temp_row_sum > path_row_sum:
temp_row_sum = path_row_sum
temp_row_index = row
return adj_list.vertexs[temp_row_index], paths[temp_row_index], path_weight[temp_row_index], temp_row_sum
test_adj_matrix.py
from graph.adj_matrix import VertexNode, ArcNode, AdjMatrix, create_adj_matrix, travers_graph, mini_span_tree_prim, \
mini_span_tree_kruskal, topo_sort, shortest_path_djs, shortest_path_floyd, center_vex
if __name__ == '__main__':
v0 = VertexNode('A')
v1 = VertexNode('B')
v2 = VertexNode('C')
arc1 = (v0, v1, 4)
arc2 = (v1, v0, 12)
arc3 = (v1, v2, 5)
arc4 = (v2, v0, 6)
adj_matrix = AdjMatrix()
vertexs = [v0, v1, v2]
arcs = [arc1, arc2, arc3, arc4]
create_adj_matrix(adj_matrix, vertexs, arcs, 'UDN')
centre_vertex, paths, paths_weight, sum_weight = center_vex(adj_matrix)
print((centre_vertex.name, sum_weight))
print("具体每条路径".center(50, '*'))
for i in range(adj_matrix.vex_num):
if paths[i]:
print(','.join([vex_node.name for vex_node in paths[i]]), paths_weight[i])