数据结构-最小生成树
一.最小生成树的定义

从V个顶点的图里生成的一颗树,这颗树有V个顶点是连通的,有V-1条边,并且边的权值和是最小的,而且不能有回路

二.Prim算法
Prim算法又叫加点法,算法比较适合稠密图
每次把边权最小的顶点加入到树中,最小生成树的不是唯一的,但最小边权是唯一的
Prim算法和 Dijkstra


核心代码
/*更新顶点距离树的距离*/for(W=0;W<Graph->Nv;W++)/*对图中顶点每个顶点W*/if (dist[W] != 0 && Graph->G[V][W] < INFINITY) {/*若W是V的邻接点并且未被收录*/if (Graph->G[V][W] < dist[W]) {/*若收录V使得dist[W]变小*/dist[W] = Graph->G[V][W];parent[W] = V;/*更新树*/}}
dist每个顶点的变化
dist[i]=0表示已经加入到最小生成树,距离树的距离是0,65535表示和树没有连接

全部代码
#include<iostream>
using namespace std;#define INFINITY 65535
#define MaxvertexNum 100
typedef int Vertex;
typedef int WeightType;
Vertex Visited[MaxvertexNum];
Vertex parent[MaxvertexNum];/*边的定义*/
typedef struct ENode* PtrToENode;
struct ENode
{Vertex V1, V2;WeightType Weight;/*边权*/
};
typedef PtrToENode Edge;typedef struct AdjVNode* PtrToAdjVNode;
struct AdjVNode
{Vertex Adjx;/*邻接点下标*/WeightType Weight;/*边权*/PtrToAdjVNode Next;/*指向下一个邻接点*/
};
typedef struct Vnode {PtrToAdjVNode FirstEdge;/*边表头结点*/}AdjList[MaxvertexNum];/*邻接表*/
typedef struct LGNode* PtrToLGNode;
typedef struct LGNode {int Nv;/*顶点数*/int Ne;/*边数*/AdjList G;
};
typedef PtrToLGNode LGraph;/*邻接表方式存储*/
/*图的定义*/
typedef struct GNode* PtrToGNode;
struct GNode {int Nv;/*顶点数*/int Ne;/*边数*/WeightType G[MaxvertexNum][MaxvertexNum];
};
typedef PtrToGNode MGraph;
LGraph Create(int Vertexnum) {Vertex V;LGraph Graph = new LGNode();Graph->Nv = Vertexnum;Graph->Ne = 0;for (V = 0; V < Graph->Nv; V++) {Graph->G[V].FirstEdge = NULL;}return Graph;
}
void Insert(LGraph Gaph, Edge E) {PtrToAdjVNode NewNode;NewNode = new AdjVNode();NewNode->Adjx = E->V2;NewNode->Next = Gaph->G[E->V1].FirstEdge;Gaph->G[E->V1].FirstEdge = NewNode;NewNode = new AdjVNode();NewNode->Adjx = E->V1;NewNode->Next = Gaph->G[E->V2].FirstEdge;Gaph->G[E->V2].FirstEdge = NewNode;
}
//插入边
void InsertEdge(MGraph Graph, Edge E) {Graph->G[E->V1][E->V2] = E->Weight;Graph->G[E->V2][E->V1] = E->Weight;
}
MGraph CreateGraph(int VertexNum) {MGraph Graph = new GNode();Graph->Nv = VertexNum;Graph->Ne = 0;for (int V = 0; V < Graph->Nv; V++)for (int W = 0; W < Graph->Nv; W++)Graph->G[V][W] = INFINITY;return Graph;
}
MGraph BuildGraph() {MGraph Graph;Edge E;int Nv;/*顶点*/cin >> Nv;Graph = CreateGraph(Nv);cin >> Graph->Ne;if (Graph->Ne != 0) {for (int i = 0; i < Graph->Ne; i++) {E = new ENode();cin >> E->V1 >> E->V2 >> E->Weight;InsertEdge(Graph, E);}}return Graph;}
Vertex FindMinDist(MGraph Graph, WeightType dist[]) {/*返回未被收录顶点中dist最小者*/Vertex MinV, V;WeightType MinDist = INFINITY;for (V = 0; V < Graph->Nv; V++) {if (dist[V] != 0 && dist[V] < MinDist) {MinDist = dist[V];MinV = V;}}if (MinDist < INFINITY)return MinV;else return 0;
}
int Prim(MGraph Graph, LGraph& MST) {/*将最小生成树保存为邻接表存储的图MST,返回最小权重和*//*dist表示顶点到树的距离*/ /*权重*/WeightType dist[MaxvertexNum], Tota1Weight;Vertex V, W;int VCount;Edge E;/*初始化。默认初始点下标是0*/for (V = 0; V < Graph->Nv; V++) {/*这里假设V到W没有直接边,则Graph->G[V][W]定义INF*/dist[V] = Graph->G[0][V];parent[V] = 0;/*暂且定义所以顶点的父亲结点都是初始化0*/}Tota1Weight = 0;/*初始化权重*/VCount = 0;/*初始化收入的顶点个数*//*创建一个没有边的邻接表*/MST = Create(Graph->Nv);E = new ENode();/*将初始点0收录MST*/dist[0] = 0;VCount++;parent[0] = -1;/*当前树根是0*/while (1) {V = FindMinDist(Graph,dist);/*V=未被收录顶点中dist最小者*/if (V == 0)/*若这样的V不存在*/break;/*算法结束*/E->V1 = parent[V];/*父亲顶点*/E->V2 = V;/*子结点*/E->Weight = dist[V];Insert(MST, E);Tota1Weight += dist[V];dist[V] = 0;/*将顶点收录集合树*/VCount++;/*更新顶点距离树的距离*/for(W=0;W<Graph->Nv;W++)/*对图中顶点每个顶点W*/if (dist[W] != 0 && Graph->G[V][W] < INFINITY) {/*若W是V的邻接点并且未被收录*/if (Graph->G[V][W] < dist[W]) {/*若收录V使得dist[W]变小*/dist[W] = Graph->G[V][W];parent[W] = V;/*更新树*/}}}/*while结束*/if (VCount < Graph->Nv)/* MST中收的顶点不到|V|个*/Tota1Weight = 0;return Tota1Weight;
}void DFS(LGraph Graph, Vertex V) {cout << V << endl;PtrToAdjVNode W;Visited[V] = 1;for (W = Graph->G[V].FirstEdge; W; W = W->Next) {if (Visited[W->Adjx] == 0) {DFS(Graph, W->Adjx);}}}
int main()
{MGraph G = BuildGraph();LGraph Gr =NULL;Prim(G,Gr);DFS(Gr, 0);for (int i = 0; i < G->Nv; i++)cout << i<<" " << parent[i] << endl;return 0;
}
/*
*
6 10
0 1 6
0 2 1
0 3 5
1 4 3
3 2 4
1 2 5
4 2 6
3 5 2
5 2 4
4 5 6
*/
三.Kruskal算法
Kruskal算法又叫加边法,算法比较适合稀疏图


代码
#include<iostream>
using namespace std;
#define MaxVertexNum 100
typedef int Vertex;
typedef int WeightType;
typedef Vertex ElementType;/*默认元素可以用非负正数表示*/
typedef Vertex SetName;/*默认用根结点的下标作为集合名称*/
typedef ElementType SetType[MaxVertexNum];/*假设集合元素下标从0开始*/
Vertex Visited[MaxVertexNum];
typedef struct ENode* PtrToENode;struct ENode
{Vertex V1, V2;WeightType Weight;
};
typedef PtrToENode Edge;typedef struct AdjVNode* PtrToAdjVNode;struct AdjVNode
{Vertex Adjx;/*邻接点下标 */WeightType Weight;/*边权重*/PtrToAdjVNode Next;/*向下下一个邻接点*/
};
typedef struct Vnode {PtrToAdjVNode FirstEdge;/* 边表头指针*/}AdjList[MaxVertexNum];
typedef struct GNode* PtrToGNode;
typedef struct GNode {int Nv;/*顶点个数*/int Ne;/*边的个数*/AdjList G;
};
typedef PtrToGNode LGraph;/*邻接表方式存储*/void InsertEdge(LGraph Graph, Edge E);
LGraph CreateGraph(int Vertexnum) {Vertex W, V;LGraph Graph = new GNode();Graph->Nv = Vertexnum;Graph->Ne = 0;for (V = 0; V < Graph->Nv; V++) {Graph->G[V].FirstEdge = NULL;}return Graph;
}
LGraph BuildGraph() {int Nv;Vertex V;Edge E;cin >> Nv;LGraph Graph = CreateGraph(Nv);cin >> Graph->Ne;if (Graph->Ne != 0) {for (V = 0; V < Graph->Ne; V++) {E = new ENode();cin >> E->V1 >> E->V2 >> E->Weight;InsertEdge(Graph, E);}}return Graph;
}
void InsertEdge(LGraph Graph, Edge E) {PtrToAdjVNode W;W = new AdjVNode();W->Adjx = E->V2;W->Weight = E->Weight;W->Next = Graph->G[E->V1].FirstEdge;Graph->G[E->V1].FirstEdge = W;W = new AdjVNode();W->Adjx = E->V1;W->Weight = E->Weight;W->Next = Graph->G[E->V2].FirstEdge;Graph->G[E->V2].FirstEdge = W;}
void InitializeVSet(SetType S, int N) {/*初始化并查集*/ElementType X;for (X = 0; X < N; X++)S[X] = -1;
}
void Union(SetType S, SetName Root1, SetName Root2) {/*这里默认Root1和Root2是不同集合的根节点*/if (S[Root2] < S[Root1]) { /*如果集合2比较大*/S[Root2] += S[Root1];/*集合1并入集合2*/S[Root1] = Root2;}else {S[Root1] += S[Root2];/*集合2并入集合1*/S[Root2] = Root1;}
}
SetName Find(SetType S, ElementType X) {/*默认集合元素全部初始化为-1*/if (S[X] < 0)/*找到集合的根*/return X;elsereturn S[X] = Find(S, S[X]);/*路径压缩*/
}
bool ChekCycle(SetType VSet, Vertex V1, Vertex V2) {/*检查连接V1和V2的边是否在现有的最小生成树子集中构成回来*/Vertex Root1, Root2;Root1 = Find(VSet, V1);/*得到V1所属的连通集名称*/Root2 = Find(VSet, V2);/*得到V2所属的连通集名称*/if (Root1 == Root2)/*若V1和V2已经连通,则该边不能要*/return false;else {/*否则改边可以被收集同时将V1和V2并入同一连通集*/Union(VSet, Root1, Root2);return true;}
}/*边的最小堆*/
/*将N个元素的边数组以ESet[p]为根的子堆调整为关于Weight的最小堆*/
void PerDown(Edge ESet,int p,int N) {//直接用数组,不用heap结构了int Parent, Child;struct ENode X;X = ESet[p];for (Parent = p; (Parent * 2 + 1) < N; Parent = Child) {Child = Parent * 2 + 1;if ((Child != N - 1) && (ESet[Child].Weight > ESet[Child + 1].Weight))Child++;if (X.Weight <= ESet[Child].Weight)break;else/*下滤*/ESet[Parent] = ESet[Child];}ESet[Parent] = X;
}
/*将图的边存入数组ESet,并且初始化为最下堆*/
void InitializeESet(LGraph Graph, Edge ESet) {Vertex V;PtrToAdjVNode W;int ECount;/*将图的边存入数组ESet*/ECount = 0;for(V=0;V<Graph->Nv;V++)for(W=Graph->G[V].FirstEdge;W;W=W->Next)if (V < W->Adjx) {/*避免重复录入无向图的边 只收V1<V2的边*/ESet[ECount].V1 = V;ESet[ECount].V2 = W->Adjx;ESet[ECount++].Weight = W->Weight;}/*初始化最小堆*/for (ECount = Graph->Ne / 2; ECount >= 0; ECount--)PerDown(ESet, ECount, Graph->Ne);
}
void Swap(struct ENode* a, struct ENode* b) {struct ENode* c;c = a;a = b;b = c;
}
/*给定当前堆的大小CurrentSize,将当前最小边位置弹出并调整*/
int GetEdeg(Edge ESet, int CurrentSize) {Swap(&ESet[0], &ESet[CurrentSize - 1]);/*将最小边与当前堆的最后一个位置的边交换*/PerDown(ESet, 0, CurrentSize - 1);/*将剩下的边继续调整成最小堆*/return CurrentSize - 1;/*返回最小边所在位置*/
}
int Kruskal(LGraph Graph, LGraph& MST) {WeightType TotalWeight;int ECount, NextEdge;SetType VSet;/*顶点数组*/Edge ESet;//边数组InitializeVSet(VSet, Graph->Nv);/*初始化顶点并查集*/ESet = (Edge)malloc(sizeof(struct ENode) * Graph->Ne);//ESet = new ENode[Graph->Ne];InitializeESet(Graph, ESet);/*初始化边的最小堆*///创建MSV图MST = CreateGraph(Graph->Nv);TotalWeight = 0;ECount = 0;NextEdge = Graph->Ne;//原始边集合的规模while (ECount < Graph->Nv - 1) {//当收集的边下与顶点数-1时NextEdge = GetEdeg(ESet, NextEdge);if (NextEdge < 0)//边收集已经空break;if (ChekCycle(VSet, ESet[NextEdge].V1, ESet[NextEdge].V2))//如果不构成回来{// 插入边到MST中InsertEdge(MST, ESet + NextEdge);//相当于&ESet[NextEdge] ;TotalWeight += ESet[NextEdge].Weight;ECount++;}}//while循环结束 if (ECount < Graph->Nv - 1)TotalWeight = -1;//设置错误标准return TotalWeight;
}
void DFS(LGraph Graph, Vertex V) {cout << V << endl;PtrToAdjVNode W;Visited[V] = 1;for (W = Graph->G[V].FirstEdge; W; W = W->Next) {if (Visited[W->Adjx] == 0) {DFS(Graph, W->Adjx);}}}
int main()
{LGraph Graph = BuildGraph();LGraph MST = NULL;Kruskal(Graph, MST);DFS(MST, 0);for(int i=0;i<Graph->Ne;i++)return 0;
}
相关文章:
数据结构-最小生成树
一.最小生成树的定义 从V个顶点的图里生成的一颗树,这颗树有V个顶点是连通的,有V-1条边,并且边的权值和是最小的,而且不能有回路 二.Prim算法 Prim算法又叫加点法,算法比较适合稠密图 每次把边权最小的顶点加入到树中࿰…...
mac启动jmeter
// 设置使用java8,使用21版本会有问题 export JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/ export PATH$JAVA_HOME/bin:$PATH cd /Users/user/software/apache-jmeter-5.1.1 //设置不使用代理 sh jmeter -Jhttp.proxyHost -J…...
spring学习笔记之静态代理和动态代理
在 Spring 开发中,静态代理和动态代理是实现面向切面编程(AOP)的两种常见方式。两者的主要区别在于代理类的生成时间和方式。 静态代理 定义 静态代理是由开发者或工具在编译期明确创建代理类的方式,代理类和目标类在程序运行前就已经存在。 特点 代理类明确存在:需要…...
qemu搭建aarch64
qemu工具搭建aarch64系统 下载准备 下载qemu: https://qemu.weilnetz.de/w64/2022/qemu-w64-setup-20220831.exe 下载固件:https://publishing-ie-linaro-org.s3.amazonaws.com/releases/components/kernel/uefi-linaro/16.02/release/qemu64/QEMU_EFI.fd?Signat…...
delphi IDE 插件DelphiIDEPlugin_SearchProject,用于从项目组中查找项目
delphi IDE 插件DelphiIDEPlugin_SearchProject,用于从项目组中查找项目 安装后在菜单Tools下第一个子菜单项查找项目 delphiIDE插件DelphiIDEPlugin-SearchProject,用于从项目组中查找项目资源-CSDN文库...
【Vue】Scoped、组件间通信、Props检验
目录 Scoped 作用 *原理 组件通信 前置知识 什么是组件通信 为什么需要组件通信 如何进行组件通信 如何辨别两个组件的关系 父子组件通信 父传子 子传父 非父子组件通信 祖先传后代 语法 任意两个组件通信 步骤 Props校验 props是什么 作用 语法 组件的…...
openbmc dbus架构简析(二)
1.说明 以前看内核代码觉得难,是因为内核代码涉及到硬件原理与算法结构和层次递进的代码逻辑,现在的应用层因为业务的复杂与代码和内核的交互接口复杂,也变得有些难度了。 这篇文章是继:openbmc dbus架构简析的第二篇文章。 首先贴出来前篇…...
【二分查找】Leetcode例题
【1】69. x 的平方根 - 力扣(LeetCode) 🍡解题思路:首先想到的是暴力查找,从1开始依次比较x与num*num的大小,然后找出满足num*num<x且(num1)*(num1)>x的num值;再来看看能不能优化一下&…...
gitlab配置调试minio
官方文档 rails console 调试 查看配置Settings.uploads.object_store加载minio clientrequire fog/awsfog_connection Fog::Storage.new(provider: AWS,aws_access_key_id: 你的MINIO_ACCESS_KEY,aws_secret_access_key: 你的MINIO_SECRET_KEY,region: <S3 region>,e…...
Vue实战技巧:如何展示附件(PDF、MP4、Excel、Zip等)并修改名称下载
大家好,今天给大家分享一篇关于在Vue项目中展示附件(PDF、MP4、Excel、Zip等)并修改名称下载的教程。在实际开发过程中,这个功能非常实用,下面我们就一起来学习一下。 一、准备工作 首先,确保你的项目中已经…...
AI证件照制作 API 对接说明
AI证件照制作 API 对接说明 本文将介绍一种 AI证件照制作 API 对接说明,它是可以通过输入人像照片URL以及自己喜欢的模板来制作各种风格的证件照。 接下来介绍下 AI证件照制作 API 的对接说明。 申请流程 要使用 API,需要先到 AI证件照制作 API?inv…...
Macos用brew安装Nodejs亲手教程
首先确保brew已安装,搜索node资源,命令如下: brew search nodejs 演示结果如下: 安装nodejs brew install node22 或 brew install node 出现如下界面 表示正在安装,安装成功后,提示如下信息࿱…...
Node.js 新手教程
1、nodejs简介 Node.js 是一个开源和跨平台的 JavaScript 运行时环境。它是几乎所有类型项目的流行工具! Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的核心)。这使得 Node.js 的性能非常出色。 Node.js 应用程序在单个进…...
Latex转word(docx)或者说PDF转word 一个相对靠谱的方式
0. 前言 投文章过程中总会有各种各样的要求,其中提供word格式的手稿往往是令我头疼的一件事。尤其在多公式的文章中,其中公式转换是一个头疼的地方,还有很多图表,格式等等,想想就让人头疼欲裂。实践中摸索出一条相对靠…...
前端热门面试题目——React、Node
img 标签的 srcset 属性的作用 srcset 属性允许开发者为不同设备或分辨率提供多个图像选项,优化加载的图片以适应设备的屏幕大小和分辨率。这提高了性能和用户体验。 示例: <img src"default.jpg" srcset"small.jpg 480w, medium.j…...
Ansible自动化一键部署单节点集群架构
自动化部署利器:Ansible 一键部署脚本 在现代IT基础设施管理中,Ansible以其简洁、强大的自动化能力脱颖而出。以下是精心打造的Ansible自动化一键部署脚本,旨在简化部署流程,提升效率,确保一致性和可靠性。 通过这个…...
电脑插入耳机和音响,只显示一个播放设备
1. 控制面板-硬件和声音-Realtek高清音频-扬声器-设备高级设置-播放设备里选择使用前部和后部输出设备同时播放两种不同的音频流 在声音设置中就可以看到耳机播放选项...
家政小程序开发,打造便捷家政生活小程序
目前,随着社会人就老龄化和生活压力的加重,家政服务市场的需求正在不断上升,家政市场的规模也正在逐渐扩大,发展前景可观。 在市场快速发展的影响下,越来越多的企业开始进入到市场中,同时家政市场布局也发…...
tcpdump抓包wireshark分析
背景 分析特定协议的数据包,如 HTTP、DNS、TCP、UDP 等,诊断网络问题,例如连接故障、延迟和数据包丢失。 大概过程 1.安装tcpdump yum update yum install tcpdump2.抓包,从当前时间起,一小时后停止,…...
文件无法直接拖入zotero
解决方法:取消管理员权限打开zotero。 具体如下:右键zotero应用程序,打开属性,选择“兼容性”,点击底下的“更改所有用户的设置”,在弹出的框中取消“以管理员身份运行此程序”。如下所示:...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
