数据结构与算法--克鲁斯卡尔算法 最小生成树 Python详细实现克鲁斯卡尔算法 Python详细实现最小生成树

news/2024/7/7 13:11:36

阅读目录

      • 基本概述
      • 克鲁斯卡尔算法图解
      • 克鲁斯卡尔算法分析
      • Python代码实现
        • 补充知识点:如何获取int(long)和 float 的最值
        • 完整代码实现

基本概述

  • 先看一个应用场景:
    在这里插入图片描述
  • 克鲁斯卡尔算法介绍:

在这里插入图片描述

克鲁斯卡尔算法图解

  • 还是以上面的公交站图来解释:
  • 最小连通子图(最小生成树):
    在这里插入图片描述
  • 以上图(G4)来说明,假设用数组 R 来保存最小生成树的结果:
    在这里插入图片描述
    在这里插入图片描述
  • 详细描述:

在这里插入图片描述

克鲁斯卡尔算法分析

在这里插入图片描述

  • 如何判断是否构成回路:

在这里插入图片描述

  • 解释上面为什么各点的终点是F:

在这里插入图片描述
在这里插入图片描述
依次将边加入到最小生成树后,形成了一条相连的轨迹(如上图),C 能到到的最后位置就是F,同理D、E也是;对于目前F来说,它的终点就是自身F;所以这几条边都有终点了!

在这里插入图片描述

Python代码实现

补充知识点:如何获取int(long)和 float 的最值

  • 获取 int 型的最大值
import sys

print(sys.maxsize) # 9223372036854775807
# 说明:这个应该为长整形long的最大值,我们对照下Java获取最大的结果来看
'''
Java中获取基本数据类型的最值的方法: 调用基本数据类型的包装类的MIN_VALUE与MAX_VALUE属性即可
具体如下:
- Integer.MIN_VALUE ⇒ -2147483648
- Integer.MAX_VALUE ⇒ 2147483647
- Long.MIN_VALUE ⇒ -9223372036854775808
- Long.MAX_VALUE ⇒ 9223372036854775807
- Float.MIN_VALUE ⇒ 1.4E-45
- Float.MAX_VALUE ⇒ 3.4028235E38
- Double.MIN_VALUE ⇒ 4.9E-324
- Double.MAX_VALUE ⇒ 1.7976931348623157E308
'''

# 注意 Python3 没有Python2 中的sys.maxint方法
  • 获得 float 型的最大值

(1)Python中可以用如下方式表示正、负无穷:

float("inf") # 注意着不是字符串,最大的浮点数就是这个'inf'
print(type(float('inf'))) # <class 'float'>
float("-inf")

(2)利用 inf 做简单加、乘算术运算仍会得到 inf

>>> 1 + float('inf')
inf
>>> 2 * float('inf')
inf

(3)inf 乘以0会得到 not-a-number(NaN);除了inf外的其他数除以inf,会得到0

>>> 0 * float("inf")
nan

>>> 233 / float('inf')
0.0
>>> float('inf') / float('inf')
nan
  • 运用到本次例子:为了更加好看,我们选取float类型的最值来表示
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(len(vertex_data)):
                if self.matrix[i][j] != self.inf:
                    self.edge_num += 1

    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()


if __name__ == '__main__':
    char_vertex = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    '''用 浮点型 最大值 float('inf') '''
    array_matrix = [[0, 12, float('inf'), float('inf'), float('inf'), 16, 14],
                    [12, 0, 10, float('inf'), float('inf'), 7, float('inf')],
                    [float('inf'), 10, 0, 3, 5, 6, float('inf')],
                    [float('inf'), float('inf'), 3, 0, 4, float('inf'), float('inf')],
                    [float('inf'), float('inf'), 5, 4, 0, 2, 8],
                    [16, 7, 6, float('inf'), 2, 0, 9],
                    [14, float('inf'), float('inf'), float('inf'), 8, 9, 0]]
    '''用 int 型号的最大值,默认是 int[8]'''
    # array_matrix = [[0, 12, sys.maxsize, sys.maxsize, sys.maxsize, 16, 14],
    #                 [12, 0, 10, sys.maxsize, sys.maxsize, 7, sys.maxsize],
    #                 [sys.maxsize, 10, 0, 3, 5, 6, sys.maxsize],
    #                 [sys.maxsize, sys.maxsize, 3, 0, 4, sys.maxsize, sys.maxsize],
    #                 [sys.maxsize, sys.maxsize, 5, 4, 0, 2, 8],
    #                 [16, 7, 6, sys.maxsize, 2, 0, 9],
    #                 [14, sys.maxsize, sys.maxsize, sys.maxsize, 8, 9, 0]]
    g = GMap(char_vertex, array_matrix)
    g.print_test()
# float 型
'''
0 12 inf inf inf 16 14 
12 0 10 inf inf 7 inf 
inf 10 0 3 5 6 inf 
inf inf 3 0 4 inf inf 
inf inf 5 4 0 2 8 
16 7 6 inf 2 0 9 
14 inf inf inf 8 9 0 
'''
# int 型
'''
0 12 9223372036854775807 9223372036854775807 9223372036854775807 16 14 
12 0 10 9223372036854775807 9223372036854775807 7 9223372036854775807 
9223372036854775807 10 0 3 5 6 9223372036854775807 
9223372036854775807 9223372036854775807 3 0 4 9223372036854775807 9223372036854775807 
9223372036854775807 9223372036854775807 5 4 0 2 8 
16 7 6 9223372036854775807 2 0 9 
14 9223372036854775807 9223372036854775807 9223372036854775807 8 9 0 
'''
# 为了好看,我们就不用int最大值了,直接用浮点型最大值 float('inf')

完整代码实现

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.vertex_data)):
            if self.vertex_data[i] == ver_data:  # 找到,返回顶点下标
                return i
        return -1  # 找不到,返回-1

    # 获取图中的边,放到EData数组中
    def get_edges(self):
        """
        功能:获取图中边,放到EData[] 数组中,后面需要遍历该数组
        是通过matrix 邻接矩阵来获取
        EData[] 形式[['A','B',12],['B','F',7],....]
        :return:
        """
        index = 0
        edges = [0] * self.edge_num
        for i in range(len(self.vertex_data)):
            for j in range(i + 1, len(self.vertex_data)):
                if self.matrix[i][j] != self.inf:
                    edges[index] = EData(self.vertex_data[i], self.vertex_data[j], self.matrix[i][j])
                    index += 1
        return edges

    def get_end(self, ends: [], i: int):
        """
        获取下标为i的顶点的终点,用来判断两个顶点的终点是否相同,是否会形成回路
        :param self:
        :param ends: 数组就是记录了各个顶点对应的终点是哪个,ends 数组是在遍历过程中,逐步形成的
        :param i: 表示传入的顶点对应的下标
        :return: 返回的就是 下标为i的整个顶点对应的终点的下标
        """
        while ends[i] != 0:
            i = ends[i]
        return i

    def kruskal(self):
        index: int = 0  # 表示最后结果数组的索引
        ends: [] = [0] * self.edge_num  # 用于保存“已有最小生成树”中的每个顶点在最小生成树中的终点
        # 创建结果数组,保存最后的最小生成树
        result = [0] * self.edge_num
        # 获取图中所有边的集合,一共12条边
        edges = self.get_edges()
        # 按照边的权值大小进行排序
        self.sort_edges(edges)
        # 遍历edges数组,将边添加到最小生成树中时,判断是否形成了回路
        for i in range(self.edge_num):
            # 获取到第i条边的第一个顶点(起点)
            p1: int = self.get_position(edges[i].start)  # p1=4
            # 获取到第i条边的第2个顶点
            p2: int = self.get_position(edges[i].end)  # p2=5
            # 获取p1这个顶点在已有的最小生成树中对应的终点
            m: int = self.get_end(ends, p1)  # m=4 初始化认为终点就是本身
            # 获取p2这个顶点在已有最小生成树种的终点
            n: int = self.get_end(ends, p2)  # n=5
            # 判断是否构成回路
            if m != n:  # 没有构成回路
                ends[m] = n  # 设置m 在已有最小生成树的终点
                result[index] = edges[i]  # 有一条边加入到result数组
                index += 1

        # 统计并打印“最小生成树”
        print('最小生成树为:')
        for item in result:
            if item == 0:
                continue
            else:
                print("<%s,%s>=%d" % (item.start, item.end, item.weight), end=" | ")


# 创建一个类 EData,它的对象实例就表示一条边
class EData(object):
    def __init__(self, start: str, end: str, weight: int):
        self.start = start
        self.end = end
        self.weight = weight


if __name__ == '__main__':
    char_vertex = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    '''用 浮点型 最大值 float('inf') '''
    array_matrix = [[0, 12, float('inf'), float('inf'), float('inf'), 16, 14],
                    [12, 0, 10, float('inf'), float('inf'), 7, float('inf')],
                    [float('inf'), 10, 0, 3, 5, 6, float('inf')],
                    [float('inf'), float('inf'), 3, 0, 4, float('inf'), float('inf')],
                    [float('inf'), float('inf'), 5, 4, 0, 2, 8],
                    [16, 7, 6, float('inf'), 2, 0, 9],
                    [14, float('inf'), float('inf'), float('inf'), 8, 9, 0]]
    '''用 int 型号的最大值,默认是 int[8]'''
    # array_matrix = [[0, 12, sys.maxsize, sys.maxsize, sys.maxsize, 16, 14],
    #                 [12, 0, 10, sys.maxsize, sys.maxsize, 7, sys.maxsize],
    #                 [sys.maxsize, 10, 0, 3, 5, 6, sys.maxsize],
    #                 [sys.maxsize, sys.maxsize, 3, 0, 4, sys.maxsize, sys.maxsize],
    #                 [sys.maxsize, sys.maxsize, 5, 4, 0, 2, 8],
    #                 [16, 7, 6, sys.maxsize, 2, 0, 9],
    #                 [14, sys.maxsize, sys.maxsize, sys.maxsize, 8, 9, 0]]
    g = GMap(char_vertex, array_matrix)
    print('图的邻接矩阵为:')
    g.print_test()
    '''测试一下图的各条边的信息'''
    print('图原先的边信息:')
    for item in g.get_edges():
        print(item.start, item.end, item.weight, end=" | ")
    print()
    print('原先总共有:%d 条边' % g.edge_num)
    '''测试一下排序'''
    # edges_array = g.get_edges()
    # g.sort_edges(edges_array)
    # for item in edges_array:
    #     print(item.start, item.end, item.weight, end=" | ")
    '''获取最小生成树'''
    g.kruskal()
'''输出结果:
图的邻接矩阵为:
0 12 inf inf inf 16 14 
12 0 10 inf inf 7 inf 
inf 10 0 3 5 6 inf 
inf inf 3 0 4 inf inf 
inf inf 5 4 0 2 8 
16 7 6 inf 2 0 9 
14 inf inf inf 8 9 0 
图原先的边信息:
A B 12 | A F 16 | A G 14 | B C 10 | B F 7 | C D 3 | C E 5 | C F 6 | D E 4 | E F 2 | E G 8 | F G 9 | 
原先总共有:12 条边
最小生成树为:
<E,F>=2 | <C,D>=3 | <D,E>=4 | <B,F>=7 | <E,G>=8 | <A,B>=12 | 

'''

http://www.niftyadmin.cn/n/2574510.html

相关文章

应用 JD-Eclipse 插件实现 RFT 中 .class 文件的反向编译

概述 反编译是一个将目标代码转换成源代码的过程。而目标代码是一种用语言表示的代码 , 这种语言能通过实机或虚拟机直接执行。文本所要介绍的 JD-Eclipse 是一款反编译的开源软件&#xff0c;它是应用于 Eclipse 开发平台的插件&#xff0c;它可以帮助开发人员在调试程序的过程…

C语言作业小学生的算术题,C语言大型作业-教小学生算数.doc

..《C语言工程训练》课程设计题目&#xff1a; 教小学生算数学 生 学 号 &#xff1a;学 生 姓 名 &#xff1a;指 导 教 师 &#xff1a;需求分析通过此系统实现以下功能做个位数&#xff0c;十位数的加&#xff0c;减&#xff0c;乘和除&#xff0c;减法不能得负数&#xff0…

Linux常用功能脚本

设置定时任务crontab -e 1 0 * * * /bin/find /mnt/tomcat/logs/ -mtime 3 -type f -name "*.log" -exec /bin/rm -rf {} \; 每天凌晨一分定时清除Tomcat的日志脚本linux下Tomcat自动备份 1、页面文件在/home/edn/tomcat6/webapps目录下&#xff0c;备份文件存放在/h…

c语言中哪个字母不能在数字后面表示类型,C语言程序设计(40学时)-中国大学mooc-题库零氪...

第一周&#xff1a;程序设计与C语言1.1 计算机和编程语言随堂测验1、计算机本身最擅长的能力是&#xff1f;A、推理B、想像C、重复D、分析2、编程语言是和计算机交谈的语言3、计算机(CPU)可以直接运行人类编写的程序1.2 C语言随堂测验1、关于C语言&#xff0c;以下说法错误的有…

结合领域驱动设计的SOA分布式软件架构 (转)

http://www.cnblogs.com/leslies2/archive/2011/12/12/2272722.html#转载于:https://www.cnblogs.com/mynameltg/p/4254991.html

数据结构与算法--二进制详解 Python二进制算法详解 史上最详细的二进制讲解 彻底搞懂原码、反码、补码 Python的负数二进制表示形式

阅读目录原码、反码、补码机器数 和 真值原码、反码、补码的基础Python中负数的处理负数的补码如何转成十进制位运算符 和 移位运算符基本概述妙用二进制涉及的算法原码、反码、补码 机器数 和 真值 机器数&#xff1a; 一个数在计算机中的二进制表示形式, 叫做这个数的机器数…

红外线stm32 c语言程序,C语言程序设计之STM32,在这里轻松学习嵌入式编程

C语言是面向过程的&#xff0c;而C&#xff0b;&#xff0b;是面向对象的C和C的区别&#xff1a;C是一个结构化语言&#xff0c;它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程&#xff0c;对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制…

总结的一些JavaScript的冷知识

1、!!将一个值方便快速转化为布尔值 console.log( !!windowtrue );2、不声明第三个变量实现交换 var a1,b2; a[b,ba][0];//执行完这句代码之后 a的值为2 b的值为1了3、&&和||的用法 &#xff08;学会了立马感觉高大尚了吧&#xff09; 用代码说话吧 var day(new Date).…