数据结构-最小生成树
一.最小生成树的定义
从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应用程序,打开属性,选择“兼容性”,点击底下的“更改所有用户的设置”,在弹出的框中取消“以管理员身份运行此程序”。如下所示:...

使用 useMemo 和 React.memo 优化 React 组件渲染
在 React 中,性能优化是一个重要的主题,特别是在复杂的组件树中。本文将演示如何在同一个父组件中使用 useMemo 和 React.memo 来优化子组件的渲染。 1. 组件结构 创建一个父组件,包含两个子组件: MemoChild:使用 R…...

ISAAC SIM踩坑记录--添加第三方3D场景
ISAAC SIM仿真首先就是要有合适的3D场景,官方提供了一些场景,如果不能满足要求,那就只能自己建。 对于我这种不会3D建模的菜鸟,只能到网上下载了,sketchfab就是一个不错的平台,有不少免费资源可以下载。 …...

Git 详解
Git 详解 Git 是一个分布式版本控制系统,用于高效地管理项目代码的版本历史。它是目前最流行的版本控制工具之一,广泛应用于软件开发领域。Git 的分布式架构允许开发者在本地进行代码的版本管理,并与远程仓库同步,实现团队协作。…...

Linux操作系统3-文件与IO操作1(从C语言IO操作到系统调用)
上篇文章:Linux操作系统2-进程控制3(进程替换,exec相关函数和系统调用)_execv系统调用-CSDN博客 本篇代码Gitee仓库:myLerningCode 橘子真甜/linux学习 - 码云 - 开源中国 (gitee.com) 本篇重点:C语言基础IO与系统调用 目录 一.…...

【Python网络爬虫笔记】8- (BeautifulSoup)抓取电影天堂2024年最新电影,并保存所有电影名称和链接
目录 一. BeautifulSoup的作用二. 核心方法介绍2.1 构造函数2.2 find()方法2.3 find_all()方法2.4 select()方法 三. 网络爬虫中使用BeautifulSoup四、案例爬取结果 一. BeautifulSoup的作用 解析HTML/XML文档:它可以将复杂的HTML或XML文本转换为易于操作的树形结构…...

Rancher V2.7.0安装教程
1、执行Docker命令 docker run -d --privileged --restartunless-stopped -p 80:80 -p 443:443 -v /home/rancher:/var/lib/rancher --name rancher registry.cn-hangzhou.aliyuncs.com/rancher/rancher:v2.7.0 注:如果容器启动失败,参考我另外一篇文章…...

STM32MX 配置CANFD收发通讯
一、环境 MCU:STM32G0B1CEU6 CAN收发器:JIA1042 二、MX配置 配置SYS 配置canfd并开启中断,我开了两个FDCAN,配置是一样的,这里贴一下波特率的计算公式: 也就是:CAN时钟频率/预分频器/&…...

(12)时间序列预测之MICN(CNN)
文章目录 前言1. challenge 一、网络结构1. MHDecomp2. Trend-cyclical Prediction Block3. Seasonal Prediction BlockMIC LayerMerge 实验结果1.长时预测 总结参考 文章信息 模型: MICN (Multi-scale Isometric Convolution Network)关键词: 长时预测…...

嵌入式蓝桥杯学习3 外部中断实现按键
Cubemx配置 前面的配置依旧一样。 原文链接:https://blog.csdn.net/m0_74246768/article/details/144227188 1.打开cubemx,将PB0到PB1配置为GPIO_EXTI模式。 2.在System-Core中点击GPIO,选择PB0到PB2, GPIO_Mode(触…...

自由学习记录(29)
FileStream FileStream 是 .NET 中用于文件操作的重要类,位于 System.IO 命名空间中。它提供了对文件的同步和异步读写操作。以下是它的方法签名和重载的详细介绍: 构造函数签名和重载 FileStream 提供多个构造函数,允许在创建实例时指定文…...