0、说明
在学习《算法分析与设计》这门课中,实验中有利用Prim算法实现最小生成树MST。本文通过Python实现,因为初学算法,而且代码基础有点差,所以代码可能比较繁琐。如您发现代码有错误或者您有更好的建议,期待和您交流!
1、用到的Python库
import math
from queue import PriorityQueue
import pandas as pd
2、定义邻接表
class AdjList:
aList = []
def __init__(self, size):
self.aList = [[x] for x in range(size)]
def add_edge(self, u, v, weight):
self.aList[u].append({'v': v, 'w': weight})
self.aList[v].append({'v': u, 'w': weight})
3、自定义的一些函数
3.1 判断某个节点是否在优先队列中
def isExist(Q, node):
for i in Q.queue:
if i[2] == node:
return True
return False
3.2 获取某个点的所有邻接点
def getAdjV(V):
adjVs = []
for i in range(1, len(V)):
adjVs.append(V[i]['v'])
return adjVs
3.3 获取优先队列中节点v的key值
def getqKey(Q, v):
q = Q.queue
for j in q:
if j[2] == v:
return j[0]
3.4 获取u和v之间的权值
def w(a, u, v):
u = a[u] # 获取u的邻接链表
for i in range(1, len(u)):
if u[i]['v'] == v:
return u[i]['w']
return math.inf
3.5 维持小顶堆性质
def keepHeap(Q):
R = PriorityQueue()
while not Q.empty():
R.put(Q.get())
return R
4、MST-Prim
def MST_Prim(a, r):
# 存储图中所有的点
V = []
for i in range(1, 8):
V.append({'key': math.inf, 'Π': None, 'node': i})
V[r]['key'] = 0
# 创建优先队列
Q = PriorityQueue()
for i in range(7):
# 所有点入队列
Q.put([V[i]['key'], V[i]['Π'], V[i]['node']])
print(Q.queue)
wsum = []
mst = []
while not Q.empty():
minV = Q.get() # key值最小的出队列
wsum.append(minV[0])
mst.append(minV[2])
u = minV[2] # 获取是哪个节点
for v in getAdjV(a[u]):
if isExist(Q, v) and w(a, u, v) < getqKey(Q, v):
for j in Q.queue:
if j[2] == v:
j[1] = u
j[0] = w(a, u, v)
break
Q = keepHeap(Q) # 修改优先队列中节点的值之后,需要维持小顶堆的性质
print(Q.queue) # 打印优先队列
# 打印MST的权重之和
print("MST权重之和:%d" % sum(wsum))
# 打印MST上权重最大的边
print("MST上最大权重:%d" % max(wsum))
# 依次打印MST上的节点
print("MST的节点依次为:", mst)
5、测试运行
if __name__ == '__main__':
# 读取数据
input_nums = pd.read_table('input_exp7.txt', header=None, sep=" ")
v_number = input_nums.iloc[0, 0]
e_number = input_nums.iloc[0, 1]
adjList = AdjList(v_number + 1)
for i in range(1, input_nums.shape[0]):
adjList.add_edge(input_nums.iloc[i, 0], input_nums.iloc[i, 1], input_nums.iloc[i, 2])
# 获取邻接表
a = adjList.aList
for i in a:
print(i)
# 参数为邻接表和MST起点
MST_Prim(a, 1 - 1)
6、测试数据
第1 行有2个正整数n 和m,表示给定的图G 有n 个顶点和m条边,顶点编号为1,2,…,n。接下来的m行中,每行有3 个正整数u,v,w,表示图G 的一条边(u,v)及其边权w
7 9 0 #此处0为填充用的数据,后面使用不到
1 2 28
1 6 10
2 7 14
2 3 16
6 5 25
7 5 24
7 4 18
3 4 12
5 4 22