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

文章目录

  • 前言
  • 一、最小生成树
    • 树的一些概念
    • 关键特性
    • 最小生成树和最短路径的主要区别
    • 常用算法
      • 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 heapqdef 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] = root1def 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 resgraph = {'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 heapqdef prim_algorithm(graph):# 选取 '1' 作为一个独立的树,权重是 0,前驱节点是Nonepriority_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 resgraph = {'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.rhkb.cn/news/401205.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【QuikGraph】TSP旅行商问题变体之不返回起点

1、问题分析 目的:在旅行商问题的基础上,无需返回起点。相当于找到一条最短路径,能够遍历所有的顶点。起点和终点都是动态计算出来的,不是提前固定的。 这个问题也称为为计算“最短的哈密尔顿路径”。 2、解决方案 出处&#…

【无标题】mysql读写分离架构+MyCAT实现读写分离

1、读写分离的目的 数据库负载均衡: 当数据库请求增多时,单例数据库不能够满足业务 需求。需要进行数据库实例的扩容。多台数据库同时相 应请求。也就是说需要对数据库的请求,进行负载均衡 但是由于数据库服务特殊原因,数据库…

【算法速刷(7/100)】LeetCode —— 200.岛屿数量

这题是典型的深搜题&#xff0c;只需要额外记录每个格子是否被搜索过&#xff0c;然后挨个进行陆地的深度搜索即可。&#xff08;如果要使用lambda进行递归&#xff0c;需要显式指出变量的模板类型&#xff0c;不能使用auto推导&#xff09; int numIslands(vector<vector&…

MATLAB基于深度学习的车辆检测系统

如今机器视觉领域深度学习算法已经大行其道&#xff0c;也让人工智能的实现不再那么遥不可及&#xff0c;但是在目标检测领域&#xff0c;让计算机超越人类还需让更多的人参与进来继续努力。如今众多的高校&#xff0c;甚至中小学已经将人工智能纳入了学习科目&#xff0c;这确…

【YOLOv5/v7改进系列】替换Neck为Gold-Yolo特征融合网络

一、导言 Gold-YOLO是一种高效的物体检测模型&#xff0c;它通过一种新的机制——Gather-and-Distribute&#xff08;GD&#xff09;机制来增强多尺度特征融合的能力&#xff0c;从而在保证实时性能的同时提高了检测精度。下面是对Gold-YOLO的主要特点和创新点的概述&#xff…

【C++ 面试 - 基础题】每日 3 题(十八)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

Web开发-CSS篇-上

CSS的发展历史 CSS&#xff08;层叠样式表&#xff09;最初由万维网联盟&#xff08;W3C&#xff09;于1996年发布。CSS1是最早的版本&#xff0c;它为网页设计提供了基本的样式功能&#xff0c;如字体、颜色和间距。随着互联网的发展&#xff0c;CSS也不断演进&#xff1a; C…

【低代码开发】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

谷粒商城实战笔记-175~177-商城业务-检索服务-检索查询接口开发

文章目录 一&#xff0c;175-商城业务-检索服务-检索查询参数模型分析抽取二&#xff0c;176-商城业务-检索服务-检索返回结果模型分析抽取三&#xff0c;177-商城业务-检索服务-检索DSL测试-查询部分四&#xff0c;178-商城业务-检索服务-检索DSL测试-聚合部分问题记录解决方案…

RCE之无参数读取文件总结

RCE漏洞(Remote Code|Command Execute)&#xff1a; 是指由于程序中预留了执行代码或者命令的接口&#xff0c;并且提供了给用户使用的界面&#xff0c;导致被黑客利用&#xff0c; 控制服务器。 代码执行漏洞原理&#xff1a; 传入php代码到执行函数的变量&#xff0c;客户端…

IIC 通信协议详解

目录 一、概述二、I2C 详解1、I2C 总线简介2、I2C 协议相关知识2.1 起始位2.2 停止位2.3 数据传输2.4 应答信号2.5 I2C 设备地址格式2.5 I2C 时序图2.5.1 I2C 写时序2.5.2 I2C 读时序2.5.3 单个/多个字节的写入/读取 3、时钟同步和仲裁3.1 时钟同步3.2 时钟仲裁 一、概述 IIC …

Fal.ai Flux 1-Pro/Viva.ai/哩布哩布AI:AI绘图部分免费工具+原图提示词Prompt

目录 #1 找软件 #2 懂提示词 #3 更难的一步&#xff0c;会英文 我个人认为&#xff0c;想要玩文生图&#xff0c;你要会3个步骤&#xff1a; #1 找软件 主流文生图软件&#xff1a;Midjourney、Stable Diffusion、Dall-E 3 巧了&#xff0c;我用的都是小众、免费的画笔工…

【Linux】守护进程:containerd的使用教程

这里写目录标题 前言一. ctr1.1 ctr CLI1.2 ctr 调试 二、 创建 container2.1 进入 NewContainer2.2 ContainerService().Create 前言 介绍了 kubelet 通过 cri 接口和 containerd 交互的过程&#xff0c;containerd 源码分析&#xff1a;启动注册流程 介绍了 containerd 作为…

赶快收藏!全网最佳Set集合详解:HashSet、TreeSet!

先赞后看&#xff0c;Java进阶马上一大半 海外geeksforgeeks网站画了这么一张Set集合的层次结构图&#xff0c;基本把Set集合涉及的常用类关系给标明了。 大家好&#xff0c;我是南哥。 一个Java学习与进阶的领路人&#xff0c;相信对你通关面试、拿下Offer进入心心念念的公司…

arthas使用

1.安装arthas 我的是windows #打开cmd&#xff0c;执行以下命令 &#xff0c;下载jar curl -O https://arthas.aliyun.com/arthas-boot.jar2.启动本地的idea项目 3.进入到jdk的bin文件夹 jdk的配置在“高级系统设置” 进入jdk的bin目录 4.启动arthas 5.arthas使用 trace 类…

Elasticsearch自动补全功能实践与Java API应用

Elasticsearch是一个强大的搜索引擎&#xff0c;它不仅支持全文搜索&#xff0c;还提供了自动补全功能&#xff0c;可以显著提升用户体验。自动补全功能允许用户在输入查询时实时显示建议项&#xff0c;帮助用户快速找到所需信息。本文将介绍如何使用Elasticsearch的RestHighLe…

探索Java Stream API:高效处理集合的利器

文章目录 一、Stream API简介1.1 什么是Stream&#xff1f;1.2 Stream的特点 二、Stream API的基本操作2.1 创建Stream2.2 中间操作2.3 终端操作 三、Stream API的高级应用3.1 并行Stream3.2 复杂数据处理3.3 Stream与Optional 四、最佳实践例子 1: 筛选和映射例子 2: 排序和收…

什么是流批一体?怎样理解流批一体?

目录 一、流式处理与批量处理概述 1.流式处理 2.批量处理 3.流批一体的定义 二、流批一体的关键特点 三、流批一体的技术实现 四、应用场景 五、实施流批一体的考虑因素 流批一体听起来很简单&#xff0c;但内涵却十分复杂。它包含了计算语义、编程模型、API、调度、执行、shuf…

html+css+js网页制作 京东首页官网 ui还原度100%

htmlcssjs网页制作 京东首页官网 ui还原度100% 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 …

微服务系列:Spring Cloud 之 Feign、Ribbon、Hystrix 三者超时时间配置

Feign 自身有超时时间配置 Feign 默认集成的 Ribbon 中也有超时时间配置 假如我们又使用了 Hystrix 来实现熔断降级&#xff0c;Hystrix 自身也有一个超时时间配置 注: spring-cloud-starter-openfeign 低一点的版本中默认集成的有 Hystrix&#xff0c;高版本中又移除了。 …