应用优先队列求最小生成树的Prim算法(Python实现)

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

7、结果

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值