【学习笔记】Matlab和python双语言的学习(最小生成树——Kruskal算法、Prim算法)

news2024/12/27 11:11:04

文章目录

  • 前言
  • 一、最小生成树
    • 树的一些概念
    • 关键特性
    • 最小生成树和最短路径的主要区别
    • 常用算法
      • 1. Kruskal算法(适合点多边少的图)
      • 2. Prim算法(适合边多点少的图)
  • 二、示例
  • 三、代码实现----Matlab
  • 四、代码实现----python
    • 1. Kruskal算法
    • 2. Prim算法
  • 总结


前言

通过模型算法,熟练对Matlab和python的应用。
学习视频链接:
https://www.bilibili.com/video/BV1EK41187QF?p=38&spm_id_from=pageDriver&vd_source=67471d3a1b4f517b7a7964093e62f7e6

一、最小生成树

树的一些概念

  • 连通图(Connected Graph):指无向图中任意两个顶点之间都有路径相连。也就是说,在一个连通图中,任意两个顶点之间都可以通过图中的边相连而相互到达。
    在这里插入图片描述

  • 树(Tree):一种无向无环连通图,它由 n n n 个节点和 n − 1 n-1 n1 条边组成。树具有很多重要的性质,比如任意两个节点之间都有唯一的路径、树中任意两个节点之间的路径长度唯一等等。

  • 生成树(Spanning Tree):指一个连通图的一棵包含所有顶点的树,它是由原图的所有顶点和边所组成的子图,且这些边构成一个树。一个图,可能有多个生成树。
    在这里插入图片描述

  • 最小生成树(Minimum Spanning Tree,简称MST)是一个连通的无向图的子图,它包含了图中所有的节点,并且边的总权重最小

关键特性

  1. 连通性:最小生成树包含图中所有的节点,并且节点之间是连通的。
  2. 无环性:最小生成树中没有环(环:从一点出发经过若干条边又回到该点的路径)。
  3. 边数:对于一个包含 ( V ) 个节点的图,最小生成树包含 ( V-1 ) 条边。
  4. 最小权重:在所有可能的生成树中,最小生成树的边的权重之和最小。

最小生成树和最短路径的主要区别

  • 最小生成树(MST):在一个无向连通图中,找到一棵树,使得它包含图中的所有节点,并且边的总权重最小。MST是关于图的全局结构的优化问题。
  • 最短路径(Shortest Path):在图中寻找两个节点之间的路径,使得路径上的边的总权重最小。最短路径是关于图的局部结构的优化问题。
  • MST:目的是连接所有节点,形成一个无环的子图,并使得边的总权重最小。
  • 最短路径:目的是找到特定两个节点之间的权重最小的路径。

常用算法

有两种主要的算法用于寻找最小生成树:Kruskal算法和Prim算法。

1. Kruskal算法(适合点多边少的图)

Kruskal算法是一种贪心算法,它通过逐步选择权重最小的边,并确保不形成环,最终构建出最小生成树。

步骤

  1. 把图 G G G 中所有边全部去掉,得到所有单独的顶点 V V V 构成的图 T T T

  2. 从图 G G G 中取出当前权值最小的边,如果该边加入 T T T 的边集合后 T T T 不形成回路,则加入 T T T,否则舍弃

  3. 重复第二步,直到 T T T 中有 n − 1 n-1 n1 条边( n n n 是定点数)

    第二步若遇到两条权值相同的最小权值边,任选一条即可,所以最小生成树可能不唯一

2. Prim算法(适合边多点少的图)

Prim算法也是一种贪心算法,它以一个节点为起点,逐步扩展生成树,每次选择与生成树相连的最小权重边。

步骤

  1. 设一空图 U U U,首先将图 G G G 中任意一顶点取出加入 U U U

  2. 从图 U U U 外并与图 U U U 连接的边中,找到权值最小的边和该边连接的顶点并入图 U U U

  3. 重复第二步,直到 U U U 中包含了所有顶点

    第二步若遇到两条权值相同的最小权值边,任选一条即可,所以最小生成树可能不唯一

二、示例

  • A国有六个城市之间一直没有通信线路,现在国家想使这六个城市通信连通
  • 六个城市,相互之间能够建设通信线缆的线路路径距离已测
  • 要求以最小的成本建设通信线路,使得这六个城市之间能够互相通信
  • 从任意顶点出发,都可以到达其他顶点,且线缆总长度最小
    在这里插入图片描述

根据要求:

  1. 从任意顶点出发,都可以到达其他顶点
  2. 线缆总长度最小

判断出该示例应使用最小生成树算法

三、代码实现----Matlab

clc,clear
% matlab中,不存在的边设置成0
% 6个顶点,初始化定义6x6的全零矩阵作为邻接矩阵
a = zeros(6);

% 注意,最小生成树是针对无向图的,每条边权重只需要设一次。1到2和2到1是同一条边
% 因此,可仅使用邻接矩阵的上三角矩阵来构造图G
a(1,[2 3])=[14 18];       % 顶点1到其他顶点的边的权重
a(2,[3:5])=[13 18 16];   % 顶点2到顶点3、顶点9的边的权重
a(3,[4 5])=[12 16];       % 同上。因为写过1到3,和2到3的边的权重,无需重复设
a(4,[5 6])=[14 19];       
a(5,6)=10;

s=cellstr(strcat('城市',int2str([1:6]')));
G=graph(a,s,'upper');  % 仅使用 A 的上三角矩阵来构造图G。
p=plot(G,'EdgeLabel',G.Edges.Weight);   % 绘制出图G

% minspantree函数求解最小生成树
% T=minspantree(G)是默认使用Prim算法
T=minspantree(G,'Method','sparse');      % 可指定使用Kruskal算法

L = sum(T.Edges.Weight)     % 对最小生成树的边的权重求和
highlight(p,T,"EdgeColor",'r','LineWidth',2.5)

运行结果:

在这里插入图片描述
在这里插入图片描述

四、代码实现----python

1. Kruskal算法

(1)表示出示例图

graph = {
    '1': {'2': 14, '3': 18},
    '2': {'1': 14, '3': 13, '4': 18, '5': 16},
    '3': {'1': 18, '2': 13, '4': 12, '5': 16},
    '4': {'2': 18, '3': 12, '5': 14, '6': 19},
    '5': {'2': 16, '3': 16, '4': 14, '6': 10},
    '6': {'4': 19, '5': 10}
}

(2)初始化节点

parent = {vertex: vertex for vertex in graph.keys()}

(3)获取边的两个节点和边的权重

# 获取所有的边
edges = []

for vertex, neighbors in graph.items():
    for neighbor, weight in neighbors.items():
        edges.append((weight,vertex, neighbor))

# 将 edges 转换为堆
heapq.heapify(edges)

(4)定义并查集函数

需要使用并查集判断一条边加入后是否形成环

并查集的相关概念见:https://blog.csdn.net/m0_65032457/article/details/141224025?spm=1001.2014.3001.5501

def find(parent, vertex):
    if parent[vertex] != vertex:
        parent[vertex] = find(parent, parent[vertex])  # 路径压缩
    return parent[vertex]

def union(parent, vertex1, vertex2):
    # 查找两个节点的根
    root1 = find(parent, vertex1)
    root2 = find(parent, vertex2)
 
    if root1 != root2:
        parent[root2] = root1

(5)使用 heapq.heappop() 函数弹出最短边

若加入该边不形成环,则使用 heapq.heappush() 函数将该边加入最小生成树。

heapq 的概念见:https://blog.csdn.net/m0_65032457/article/details/141135370?spm=1001.2014.3001.5501

while edges:
    weight, note1, note2 = heapq.heappop(edges)     
    if find(parent, note1) != find(parent, note2):
        union(parent, note1, note2)
        heapq.heappush(res, (weight, note1, note2))

Kruskal算法的完整代码

import heapq

def find(parent, vertex):
    if parent[vertex] != vertex:
        parent[vertex] = find(parent, parent[vertex])  # 路径压缩
    return parent[vertex]

def union(parent, vertex1, vertex2):
    # 查找两个节点的根
    root1 = find(parent, vertex1)
    root2 = find(parent, vertex2)
 
    if root1 != root2:
        parent[root2] = root1

def kruskal_algorithm(graph):

    # 初始化并查集
    parent = {vertex: vertex for vertex in graph.keys()}

    # 获取所有的边
    edges = []

    # 初始化一个空的堆用来存放最小生成树的结果
    res = []

    for vertex, neighbors in graph.items():
        for neighbor, weight in neighbors.items():
            edges.append((weight,vertex, neighbor))

    # 将 edges 转换为堆
    heapq.heapify(edges)

    while edges:
        weight, note1, note2 = heapq.heappop(edges)     
        if find(parent, note1) != find(parent, note2):
            union(parent, note1, note2)
            heapq.heappush(res, (weight, note1, note2))
    
    return res

graph = {
    '1': {'2': 14, '3': 18},
    '2': {'1': 14, '3': 13, '4': 18, '5': 16},
    '3': {'1': 18, '2': 13, '4': 12, '5': 16},
    '4': {'2': 18, '3': 12, '5': 14, '6': 19},
    '5': {'2': 16, '3': 16, '4': 14, '6': 10},
    '6': {'4': 19, '5': 10}
}

result = kruskal_algorithm(graph)
print(result)

运行结果:

在这里插入图片描述
数据分别代表:边的权重、节点1、节点2

2. Prim算法

算法思路:

  1. 任意选取图中的一个节点为一个独立的树
  2. 取出除这棵树外,所有与这棵树相连的节点到这棵树的距离,加入优先队列
  3. 弹出优先队列中距离这棵树最近的节点,并将其加入这棵树(更新这棵树的范围)
  4. 重复2、3步骤,直到遍历完所有的节点

代码思路:

  1. 算法角度:在 Prim 算法中,需要确定 “树” 的范围,以便找到除这棵树外,所有与这棵树相连的节点。

    代码角度:创建一个集合 visited = set() ,用来存放已访问的节点(树范围内的节点都存放于集合中),通过节点是否在集合内判断出节点是否在树中。

  2. 算法角度:找到树范围外,所有与树相连的节点

    代码角度:树范围外 ——> 节点不在集合 visited 内,与树相连 ——> 相连的节点在集合 visited 内。(通过这两个条件找出了与树相连的节点和到这棵树的距离,生成了优先队列)

完整代码思路:

(1)表示出示例图

graph = {
    '1': {'2': 14, '3': 18},
    '2': {'1': 14, '3': 13, '4': 18, '5': 16},
    '3': {'1': 18, '2': 13, '4': 12, '5': 16},
    '4': {'2': 18, '3': 12, '5': 14, '6': 19},
    '5': {'2': 16, '3': 16, '4': 14, '6': 10},
    '6': {'4': 19, '5': 10}
}

(2)初始化

# 选取 '1' 作为一个独立的树,权重是 0,前驱节点是None
priority_queue = [(0,'1',None)]

# 初始化集合,用来存放已访问的节点
visited = set()

# 存放最小生成树
res = []

(3)生成优先队列

# 更新相邻节点的距离
for neighbor, distance in graph[note1].items():
    if neighbor not in visited:   # 与节点 1 相邻的节点 1' 是否在树中
        for n, d in graph[neighbor].items():    # 取出该相邻结点 1' 的相邻结点 2'
            if n in visited:     # 相邻结点 2'在树中,代表相邻的节点 1'与树相连
                heapq.heappush(priority_queue,(d,neighbor,n))   # 加入优先队列

(4)更新树的范围

# 弹出堆中距离最小的节点
weight, note1, note2 = heapq.heappop(priority_queue)
priority_queue = []  # 清空优先队列 

if note2 != None:
    visited.add(note2)  # 将前驱节点加入已访问中 (更新树的范围)  
    res.append((weight, note1, note2))  # 更新最小生成树

visited.add(note1)  # 将该节点也加入已访问中 (更新树的范围)  

Prim算法的完整代码

import heapq

def prim_algorithm(graph):
    
    # 选取 '1' 作为一个独立的树,权重是 0,前驱节点是None
    priority_queue = [(0,'1',None)]

    # 初始化集合,用来存放已访问的节点
    visited = set()

    # 存放最小生成树
    res = []

    while priority_queue:

        # 弹出堆中距离最小的节点
        weight, note1, note2 = heapq.heappop(priority_queue)
        # print("距离最小的节点是:",weight, note1, note2)
        priority_queue = []  # 清空优先队列 

        if note2 != None:
            visited.add(note2)  # 将前驱节点加入已访问中   
            res.append((weight, note1, note2))
            # print("最小生成树进度:",res)

        visited.add(note1)  # 将该节点也加入已访问中
        # print("已访问的节点:",visited)

        # 更新相邻节点的距离
        for neighbor, distance in graph[note1].items():
            if neighbor not in visited:   # 与节点 1 相邻的节点 1' 是否在树中
                for n, d in graph[neighbor].items():    # 取出该相邻结点 1' 的相邻结点 2'
                    if n in visited:     # 相邻结点 2'在树中,代表相邻的节点 1'与树相连
                        heapq.heappush(priority_queue,(d,neighbor,n))   # 加入优先队列
                        # print("优先队列:",priority_queue)
    return res

graph = {
    '1': {'2': 14, '3': 18},
    '2': {'1': 14, '3': 13, '4': 18, '5': 16},
    '3': {'1': 18, '2': 13, '4': 12, '5': 16},
    '4': {'2': 18, '3': 12, '5': 14, '6': 19},
    '5': {'2': 16, '3': 16, '4': 14, '6': 10},
    '6': {'4': 19, '5': 10}
}

result = prim_algorithm(graph)
print(result)

运行结果:

在这里插入图片描述

总结

本文介绍了求解最小生成树的两种算法—— Kruskal和Prim,详细介绍了两种算法的求解思路。分别使用matlab和python进行了算法的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2044428.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

硬件模拟的基本原理是什么?

具体来说,这种设计方法减少了集成电路 (IC) 设计和开发的设计迭代次数,并且广泛适用于所有电力电子设计。我详细介绍了我在快速上市 IC 开发方面的经验,并将该方法与其他旨在缩短产品开发时间的技术进行了对比。 产品开发流程 图 1&#xff…

三菱定位控制(三,步进电机与定位模块的接线详情)

相信大家对前面的学习已经对前面的内容有所了解,下面就来看看步进电机,步进电机驱动器还有定位模块之间是如何接线的吧! 一,将定位模块转换为端子排 首先,我们肯定是无法之间再定位模块上直接进行接线的。所以我们需要…

基于Java中的SSM框架实现家政预约管理系统项目【项目源码+论文说明】

基于Java中的SSM框架实现家政预约管理系统演示 摘要 随着线上预约服务应用的不断普及,为了给用户提供更加便捷的服务,很多行业都实行了线上预约制,比如医疗行业的线上挂号以及交通行业预约购票等,预约服务可以帮助人们节约大量排…

Ubuntu 安装 mysql 与 远程连接配置

1、安装 mysql ubuntu 默认安装 8.0 版本: sudo apt install mysql-server安装过程中 提示 是否继续操作 y 即可 2、使用ubuntu 系统用户 root 直接进入 mysql 切换至 系统用户 su root 输入命令 可直接进入 mysql: mysql3、创建一个允许远程登录的用户 创建 …

使用国内镜像站点安装Qt6 for Mac

使用国内镜像站点安装Qt6 for Mac 从下列网址下载在线安装包 Index of /archive/online_installers (qt.io) 双击前述dmg文件,在终端执行语句 使用一句命令行语句: open qt-unified-macOS-x64-4.6.1-online/qt-unified-macOS-x64-4.6.1-online.app --…

【leetcode】回文链表-25-3

方法:快慢指针递归遍历 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) …

超吸睛!用AI绘画做沙雕图文号,有趣又解压!轻松吸粉变现!

大家好,我是画画的小强 小强可谓是小某书资深用户,最近突然刷到了某篇主打沙雕日常文案的 AI手绘插画图文号,不仅篇篇笔记上千点赞量,重点!这类图文号植入的均是报价贼高的软广,我的老天鹅!一搜…

基于vue框架的爱购电商平台256tr(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,商家,商品分类,商品信息 开题报告内容 基于Vue框架的爱购电商平台 开题报告 一、研究背景与意义 随着互联网技术的迅猛发展和消费者购物习惯的深刻变革,电子商务已成为推动全球经济增长的重要力量。然而,…

分销商城小程序系统渠道拓展

线上卖货渠道很多,想要不断提高营收和新客获取,除了自己和工具本身努力外,还需要其他人的帮助来提高商城店铺的整体销量。 搭建saas商城系统网站/小程序,后台上货,设置支付、配送、营销、精美模板商城装修等内容&…

网络研讨会 | Unlock your SAP Data:用新一代 SAP 集成方案加速释放企业核心数据价值

伴随着业务的快速发展,企业对 SAP 系统的使用逐渐深化。为了更好释放数据价值,有效驱动商业决策,将 SAP 数据与其他数据系统集成打通,已成为企业数字化发展的必然趋势。 然而,由于 SAP 系统的独特性,企业想…

Lesson 59 Is that all?

Lesson 59 Is that all? 词汇 envelope n. 信封 复数:envelopes 例句:在红色信封里有一封书信。 There is a letter in the red envelope. writing paper n. 信纸【不可数】 构成:write v. 写 writer n. 作家    相关:hand…

SQL SERVER 2008多表关联查询,关联条件用(*=、=*)无法使用,高版本数据库不兼容,报错“*=”附近有语法错误!

专业问题,已经习惯了先问AI 下图是百度AI的回复 下图是讯飞星火的回复 下面是SQL SERVER 2022数据库引擎,查询使用! 报错:“*”附近有语法错误。 查询数据库版本语法 SELECT VERSION 得到数据库版本:SQL Server 202…

【CVE-2024-38077】修复Windows 远程桌面授权服务远程代码执行漏洞记录

官方漏洞指南:Security Update Guide - Microsoft Security Response Center 受影响版本: Windows Server 2012 R2 (Server Core installation) Windows Server 2012 R2 Windows Server 2012 (Server Core installation) Windows Server 2012 Windows …

AI时代来临,程序员歇业在家,如何利用AI来赚钱?

我没有团队,就一个人,能不能用AI来赚点小钱? 当然可以,单打独斗并非阻碍,AI技术完全可以助您拓展收入来源。接下来,我将为您详细介绍10种个体利用AI提升收入的有效途径。 首先,您可以通过以下…

PRVF-4037 : CRS is not installed on any of the nodes

描述:公司要求替换centos,重新安装ORACLE LINUX RAC的数据库做备库,到时候切换成主库,安装Linux7GRID 19C 11G Oracle,顺利安装grid 19c,安装11G数据库软件的时候检测报如题错误:**PRVF-4037 …

显卡刷坏BIOS黑屏怎么办_万能救砖恢复方法来了!

电脑显卡刷bios黑屏不开机无显示无信号,是因为显卡vbios刷错文件了,找到正确的显卡BIOS文件刷回去就行了。但是黑屏进不去系统如何刷显卡BIOS呢。给大家推荐个万能刷显卡BIOS工具,名字是《离线刷bios设备》,用免拆夹子直接连接显卡…

49-DRC的设置及检查

1. DRC设置入口 2.如下设置 3.运行DRC

IDEA 解决创建新项目Maven配置变化问题

我们发现,每次创建新项目,配置好的maven路径就变了,总是恢复成IDEA自带的maven配置,我们想永久使用我们的Maven配置,该如何修改呢? 配置好要重启IDEA!!!

kubernetes k8s Daemonset 控制器 原理 讲解 配置

目录 1 DaemonSet控制器:概念、原理解读 1.1 DaemonSet概述 1.2 DaemonSet工作原理:如何管理Pod? 1.3 Daemonset典型的应用场景 1.4 DaemonSet 与 Deployment 的区别Deployment 部署的副本 Pod 会分布在各个 Node 上,每个…

Docker安全与资源

一、cgroup资源配置方法 1.cgroup概念 cgroup(control group控制族群) (1)什么是cgroup 和namespace类似,也是将进程进程分组,但是目的与namespace不一样,namespace是为了隔离进程组之前的资…