最小生成树之(克鲁斯卡尔算法)和(普里姆算法)python实现

克鲁斯卡尔算法(Kruskal):

设有一个有n个顶点的连通网N={V,E},最初先构造一个只有n个顶点,没有边的非连通图T={V, E},图中每个顶点自成一个连通分量。当在E中选到一条具有最小权值的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则将此边舍去,重新选择一条权值最小的边。如此重复下去,直到所有顶点在同一个连通分量上为止。

普里姆算法的基本思想:

普里姆算法是另一种构造最小生成树的算法,它是按逐个将顶点连通的方式来构造最小生成树的。

从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边(u0, v),将其顶点加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把该边加入到生成树的边集TE中,把它的顶点加入到集合U中。如此重复执行,直到网络中的所有顶点都加入到生成树顶点集合U中为止。

假设G=(V,E)是一个具有n个顶点的带权无向连通图,T(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则构造G的最小生成树T的步骤如下:

(1)初始状态,TE为空,U={v0},v0∈V;

(2)在所有u∈U,v∈V-U的边(u,v) ∈E中找一条代价最小的边(u′,v′)并入TE,同时将v′并入U;

重复执行步骤(2)n-1次,直到U=V为止。

克鲁斯卡尔算法和普里姆算法不同的是其寻找顺序不同,克鲁斯卡尔算法是先从边开始找,普里姆算法是先从点开始寻找,二者都是寻找图中最小生成树的方式。

下面用图来说明两种算法:
克鲁斯卡尔算法寻找最小生成树过程:
在这里插入图片描述

普里姆算法寻找最小生成树过程:

在这里插入图片描述
由此我们可以看出,两种算法得到的最小生成树是相同的,仅仅是过程不一样而已。

下面我们来通过代码实现:
克鲁斯卡尔算法实现过程:
那么我们如何判断生成树中没有环产生呢?
判断方式是这样的,判断要加入的该边的终点否在生成树中,如果没在生成树中,那么就可以加入,如果在生成树中,那么就不能加入。例如:
在这里插入图片描述

比如上图中如果生成树中已经包含了AB边,BC边,如果要加入AC边的话,那一定会构成环,为什么呢,那是因为加入AC边时,从该边的起点A出发,在已经构建好的生成树中已经有从A到C点的边A-B-C,那在加入AC边时就会产生环,所以我们的判断条件就是判断加入改边时,已经构建好的生成树中是否和该边有共同的终点,如果有,那么就不能加入改边,直到生成树中存在n-1条边时终止。

下面代码进行实现:

import sys


class GMap(object):
    def __init__(self, vertex_data: [], matrix: []):  # 传入顶点数组
        self.edge_num = 0  # 边的个数
        # self.vertex_data = vertex * [0]  # 顶点数组
        self.vertex_data = vertex_data
        # self.matrix = [[0 for row in range(len(vertex_data))] for col in range(len(vertex_data))]  # 邻接矩阵
        self.matrix = matrix
        # 使用 INF 表示两个顶点不能连通
        self.inf = float('inf')  # 获取浮点型最大值
        # self.inf = sys.maxsize # 获取整形最大值
        # 统计边的条数
        for i in range(len(vertex_data)):
            for j in range(i + 1, len(vertex_data)):
                if self.matrix[i][j] != self.inf:
                    self.edge_num += 1
        # print(self.edge_num)

    def print_test(self):  # 打印测试
        for i in range(len(self.vertex_data)):
            for j in range(len(self.vertex_data)):
                print(self.matrix[i][j], end=' ')
            print()

    # 对边进行排序处理,这里使用一下冒泡排序,其他排序方式都可以
    def sort_edges(self, edges: []):
        for i in range(len(edges) - 1):
            flag = False
            for j in range(len(edges) - 1 - i):
                if edges[j].weight > edges[j + 1].weight:
                    edges[j], edges[j + 1] = edges[j + 1], edges[j]
                    flag = True
            if not flag:
                break

    # 查找传入顶点的位置
    def get_position(self, ver_data: str):
        """
        :param ver_data: 传入顶点的值,例如:"A""B"
        :return: 找到返回ch顶点对应的下标,如果没找到,返回-1
        """
        for i in range(len(self
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值