图(邻接矩阵)知识大杂烩!!(邻接矩阵结构,深搜,广搜,prim算法,kruskal算法,Dijkstra算法,拓扑排序)(学会一文让你彻底搞懂!!)
小伙伴们大家好,今天给大家带来图(邻接矩阵)的各种知识,让你看完此文章彻底学会邻接矩阵的相关问题。
1.邻接矩阵表示方法
1.1知识讲解
我们用一个二维数组arr来表示图。若图为有向图,其中arr【i】【j】=w表示i号点和j号点之间的距离为w,如果i和j之间无路可以设定w=0或无穷。(根据个人喜好,后续代码会有不同)若图为无向图,arr【i】【j】=w表示i和j之间是否直接相连,w=1表示相连;w=0表示不相连。
1.2.相关操作及代码
1.2.1初始化
void create(int a[][5],int n,int m){for(int i=0;i<n;i++){for(int j=0;j<m;j++){a[i][j]=0;}}
}
我这里数组为5行5列,因此传参时使用a【】【5】。大家根据自己数组情况更改,或者使用全局变量。n和m为行列数。第i行代表i号点和其它点之间的关系。 我这里初始化为0,大家也可以初始化为无穷。
2.广搜(bfs)
2.1知识讲解
广度搜索我们使用队列完成。给定一个出发点i,将其入队列。拿出队列首元素,我们遍历arr数组第i行,如果arr【i】【j】不为0说明i和j直接相连,将其存入队列,直至遍历完第i行。此时队列中的元素为与i号点相连的点。(i号点已经出队列)然后再拿出队列首元素,重复上述操作,直至队列为空。应该注意的是:当我们拿出队列首元素后,就要为其打上标记,放置再将其入队列。
2.2代码
void bfs(int arr[][5],int n,int m,int start){//从start节点开始 int visited[n],i;for(int j=0;j<n;j++){visited[j]=0;}queue<int>q;q.push(start);while(!q.empty()){i=q.front();q.pop();visited[i]=1;cout<<i+1<<" ";//可以换成其它处理逻辑for(int j=0;j<m;j++){if(arr[i][j]&&!visited[j]){q.push(j);}}}cout<<endl;
}
3.深搜(dfs)
3.1知识讲解
广搜的思想是:每次将当前点的所有相连点遍历完。而深搜的思想是:若当前点找到相连点后,从相连点出发,继续寻找相连点,若找不到则返回上一层。这种思想很符合递归策略。其中,仍然需要visited标记数组防止重复找点。
3.2代码
int visited[5]={0};
void dfs(int arr[][5],int n,int m,int start){visited[start]=1;cout<<start+1<<" ";for(int i=0;i<m;i++){if(arr[start][i]&&!visited[i]){dfs(arr,n,m,i);}}
}
其中,visited数组必须为全局变量。否则递归重新进入函数会让其不断清零,起不到标记作用。
4.寻找最小生成树-prim算法
4.1最小生成树
定义:给定一个连通的无向图,最小生成树是指包含图中所有顶点的一棵树,且该树的所有边的权重之和最小。
判断是否联通我们可以使用深搜以及广搜,看能否遍历所有节点。也可以使用我之前讲过的并查集,通过不断地merge操作,看最后是否只有一个根。
相关连接:岛屿数量+并查集_岛屿数量 并查集-CSDN博客。我们在讲解时默认图是联通的。
若图有n个点,那么最小生成树会有n-1条边。这个性质用于让我们知道何时循环结束。
4.2 Prim算法知识讲解
Prim算法思想:从一个出发点开始(标记出发点),寻找与其直接相连的点,在这些点中找出与其距离最小的点将其标记。下一次操作时,凡是被标记的点都要寻找与其距离最小的点(要求所寻找的点未被标记),最终从这些距离最小点中再选出最小点将其标记。重复操作,直至找出n-1条边。
4.3代码
void clear(priority_queue<int,vector<int>,greater<int> >&q){while(!q.empty()){q.pop();}
}int prim(int arr[][5],int n,int m,int start){int visited[n],cur,sum=0,flag;priority_queue<int,vector<int>,greater<int> >q;//最小堆for(int i=0;i<n;i++){visited[i]=0;}visited[start]=1;//标记出发点for(int i=0;i<m;i++){if(arr[start][i]){//此时其他点均未被标记if(q.empty()||arr[start][i]<q.top()){flag=i;//记录距离最小点的下标}q.push(arr[start][i]);}}cur=q.top();//堆顶为距离最小值visited[flag]=1;//为该店打上标记sum=sum+cur;cout<<"选择权值"<<cur<<endl;clear(q);//清空最小堆int count=1;while(count<n-1){//开始时找到一条边,再找n-2条边,count初始为1for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(visited[i]&&!visited[j]&&arr[i][j]){if(q.empty()||arr[i][j]<q.top()){flag=j;}q.push(arr[i][j]);}}}visited[flag]=1;count++;cur=q.top();sum=sum+cur;cout<<"选择权值"<<cur<<endl;clear(q);}return sum;
}
这里使用最小堆来存储边的权重,大家注意如何找到距离最小的那个点的下标,因为开始时我就在这有点晕。
5.寻找最小生成树算法-kruskal算法
5.1知识讲解
Kruskal算法相较于prim算法较为简单,思想如下:每次从所有边中选择最短的那条,如果选择之后和之前选择的边不构成环,那么接受。如果构成环则拒绝,重新寻找。直至选择n-1条边。重点是如何判断是否成环:在此我使用了并查集的思想。不会的可以查看我之前的文章:岛屿数量+并查集_岛屿数量 并查集-CSDN博客
5.2代码
struct node{int point1;int point2;int value;
};
typedef struct node* Node;
Node createnode(){Node n=(Node)malloc(sizeof(struct node));n->point1=0;n->point2=0;n->value=0;return n;
}
//重载比较方法
struct cmp{bool operator()(struct node* a,struct node* b){return a->value>b->value;}
};
//重载哈希表
struct PairHash {template <class T1, class T2>size_t operator() (const pair<T1, T2> &pair) const {return hash<T1>()(pair.first) ^ hash<T2>()(pair.second);}
};
int find1(int *parent,int x){while(x!=parent[x]){x=parent[x];}return x;
}
void merge(int *parent,int x,int y){int fx=find1(parent,x);int fy=find1(parent,y);if(fx!=fy){parent[fy]=fx;}
}
int kruskal(int arr[][5],int n,int m){//每次选取权值最小的边不构成环取该边 priority_queue<Node,vector<Node>,cmp >p;//重载比较方法 unordered_map<pair<int,int>,int,PairHash>u;int sum=0;Node min;for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(arr[i][j]&&u.find(make_pair(i,j))==u.end()){Node n=createnode();n->point1=i;n->point2=j;n->value=arr[i][j];p.push(n);u[make_pair(i,j)]=1;u[make_pair(j,i)]=1;}}}int size=0;int parent[n];for(int i=0;i<n;i++){parent[i]=i;}while(size<n-1){min=p.top();p.pop();if(find1(parent,min->point1)!=find1(parent,min->point2)){//不构成环 cout<<"选取权值"<<min->value<<endl;size++;sum=sum+min->value;merge(parent,min->point1,min->point2);}}return sum;
}
Kruskal算法第一步:找出所有的边,并加入最小堆中。由于是无向图,比如arr【0】【1】和arr【1】【0】的边权值均为2,如果不做处理可能重复选择。因此我们使用了哈希表来解决此问题。其中哈希表key值为pair型,value为int型。(value其它类型也可以我们用不到)当i=0,j=1时,我们除了将(0,1)存入哈希表也需要将(1,0)存入哈希表,这样当i=1,j=0时就不会重复了。其中哈希表需要重载,详细见上述代码。
Kruskal算法第二步:选出最短边(堆顶),看是否和之前的边构成环。我们查看i和j的根是否相同,若相同则说明构成环,将其抛弃。否则,说明不构成环,是我们所需要的边,并将i和j合并为同一集合。我们根据堆顶要找出该边所相连的点,因此堆中应放一个结构体Node,Node中有三个元素,分别为一条边和边所连接的两个点。其中小根堆的比较方法需要我们重载,具体见上述代码。直到我们找出n-1条边时,返回sum。
对于哈希表不了解的伙伴们,可以看我之前的文章:Leetcode--两数之和(day 3)-CSDN博客
6.拓扑排序
6.1知识讲解
拓扑排序适用于有向无环图。
拓扑排序是根据点的入度来实现的。当我们遍历找到一个入度为0的点时,将其拿出并去除其影响。(将因为该点而产生的其它点的入度消除)继续遍历,直至我们找完所有点。每一轮可能有多个入度为0的点,这也就决定了拓扑排序结果不唯一。
举个例子,1->2,1->3,2->3。1的入度为0,2的入度为1,3的入度为2。我们第一次找出1,并去除其影响(1->2,1->3),此时2的入度为0,3的入度为1,我们找出2,并去除其影响(2->3),此时3的入度为0,我们找出3。此时所有点均被找出,拓扑排序结束。
6.2代码
void Toposort(int arr[][5],int n,int m){int vidited[n];for(int j=0;j<n;j++){visited[j]=0;}cout<<endl; int count[n];for(int i=0;i<n;i++){count[i]=0;}for(int i=0;i<n;i++){for(int j=0;j<m;j++){if(arr[i][j]){count[j]++;//统计入度 }}}int size=0;while(size<n){for(int i=0;i<n;i++){if(!count[i]&&!visited[i]){//入度为0并且之前没被拿出,拿出并将其影响去除 cout<<i+1<<" ";visited[i]=1;//标记此点防止重复size++;for(int j=0;j<m;j++){if(arr[i][j]){count[j]--;//去除其影响}}}}}
}
注意拿出一个点后,就要为其打上标记,防止重复拿。
7.Dijkstra算法-单元最短路径
7.1知识讲解
Dijkstra算法思想第一步:寻找与出发点最近的点。第二步:根据最近点更改其它点:如果出发点距离某个点i的距离大于出发点到最近点的距离加上最近点到i点的距离,那么更改出发点到i点的距离为出发点到最近点的距离加上最近点到i点的距离。重复n-1次操作。(因为出发点到出发点距离为0)
7.2代码
int *dijkstra(int arr[][5],int start,int n){//n为点的数量 int visited[n],min,cur;int *dist=new int[n];//初始化 for(int i=0;i<n;i++){if(arr[start][i])dist[i]=arr[start][i];elsedist[i]=88888;visited[i]=0;}for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(i==j){continue;}arr[i][j]=arr[i][j]?arr[i][j]:88888;}}
// for(int i=0;i<n;i++){
// cout<<dist[i]<<" ";
// }
// cout<<endl;dist[start]=0;visited[start]=1;for(int i=0;i<n-1;i++){//求n-1个最小值 //找距离start最短路径的点min=999999;for(int j=0;j<n;j++){if(!visited[j]&&dist[j]<min){cur=j;min=dist[j];}}dist[cur]=min;visited[cur]=1;//更新其它点 for(int j=0;j<n;j++){if(!visited[j]&&dist[cur]+arr[cur][j]<dist[j]){dist[j]=dist[cur]+arr[cur][j];}} }return dist;
}
注意当我们找到某个最小值时就要为其做上标记。另外还需要额外注意初始化问题,否则会引起很严重的错误。
关于图(邻接矩阵)的全部知识到此结束,我相信搞懂这一篇文章,你对图会有更深刻的理解!!多多点赞,感谢支持!
相关文章:
图(邻接矩阵)知识大杂烩!!(邻接矩阵结构,深搜,广搜,prim算法,kruskal算法,Dijkstra算法,拓扑排序)(学会一文让你彻底搞懂!!)
小伙伴们大家好,今天给大家带来图(邻接矩阵)的各种知识,让你看完此文章彻底学会邻接矩阵的相关问题。 1.邻接矩阵表示方法 1.1知识讲解 我们用一个二维数组arr来表示图。若图为有向图,其中arr【i】【j】w表示i号点和…...
Prometheus自定义PostgreSQL监控指标
本文我们将介绍如何在Prometheus中创建自定义PostgreSQL指标。默认情况下由postgres_export运行的查询可能不能满足用户需求,但我们可以创建自定义查询,并要求postgres_exporter公开自定义查询的结果。postgres_exporter最近被移到了Prometheus Communit…...
400行程序写一个实时操作系统(十六):操作系统中的调度策略
前言 在前面我们完成了Sparrow的临界区的代码,使用临界区,能够解决常见的并发问题,现在该完善我们的调度算法了。 调度算法在操作系统领域常常是热门的话题。不同的用途将会使用不同的调度策略。在本节,笔者将为大家介绍一些操作…...
从安灯系统看汽车零部件工厂的智能制造转型
在当今快速发展的制造业领域,汽车零部件工厂正面临着日益激烈的市场竞争和不断提高的客户需求。为了在竞争中脱颖而出,实现可持续发展,许多汽车零部件工厂纷纷踏上智能制造转型之路。而安灯系统作为一种重要的生产管理工具,在这场…...
SwiftUI(三)- 渐变、实心形状和视图背景
引言 在现代的应用的UI设计中,渐变和形状背景为界面带来了丰富的层次与视觉效果,而SwiftUI提供了一系列简单且强大的API,可以轻松实现这些效果。在这篇文章中,我们将介绍SwiftUI中的渐变、实心形状和视图背景的基础用法ÿ…...
RK3568-ota升级
ota升级 OTA(Over-the-Air)即空间下载技术。 OTA 升级是 Android 系统提供的标准软件升级方式。它功能强大,可以无损失升级系统,主要通过网络,例如 WIFI、3G/4G 自动下载 OTA 升级包、自动升级,也支持通过…...
GR-ConvNet代码详解
GR-ConvNet代码详解 文章目录 GR-ConvNet代码详解前言一、utils1.dataset_processing1.image.py1.Iamge类2.DepthImage类3.WidthImage类 2.grasp.py1. _gr_text_to_no()方法2.GraspRectangles类3.GraspRectangle类3.Grasp类4.detect_grasps方法 3.generate_cornell_depth.py4.e…...
Excel自带傅里叶分析数据处理——归一化处理
在Excel工具中,默认情况下数据处理---傅里叶分析通常不进行归一化处理,需要用户手动进行归一化处理。 (1)傅里叶变换的原理 傅里叶变换将时域信号转换为频域信号,输出的是复数形式的频率分量,包含了幅值和…...
Centos7.6版本安装mysql详细步骤
操作步骤: 1.下载Linux版本Mysql并上传至linux系统中 2.解压mysql并查询系统中是否有相关软件存在以及配置mysql,启动mysql tar -zxvf mysql-5.7.35-linux-glibc2.12-x86_64.tar.gz tar -zxvf mysql-5.7.35-linux-glibc2.12-x86_64.tar.gz rpm -qa|grep mysql ##查…...
寄宿学校:为自闭症儿童提供全面的教育和关爱
在这个多彩的世界里,每一个生命都值得被温柔以待,每一颗心灵都值得被悉心呵护。然而,自闭症儿童这一特殊群体,他们的世界却常常被误解和忽视。幸运的是,有一种教育模式——寄宿学校,正为这些孩子打开了一扇…...
LLaMA Factory环境配置
LLaMA-Factory官方文档 安装正确的torch和cuda版本 参考: PyTorch 报错解决 1.ImportError: /usr/lib/x86_64-linux-gnu/libstdc.so.6: version GLIBCXX_3.4.29 not found 参考这个解决:丝滑解决ImportError: /usr/lib/x86_64-linux-gnu/libstdc.s…...
STM32实现毫秒级时间同步
提起“时间同步”这个概念,大家可能很陌生。一时间搞不清楚是什么意思。 我理解“时间同步”可以解决多个传感器采集数据不同时的问题,让多个传感器同时采集数据。 打个比方。两个人走路,都是100毫秒走一步(频率相同是前提&…...
瑞吉外卖之com.fasterxml.jackson.dataformat.cbor.CBORFactor相关报错
1.报错:Error creating bean with name routerFunctionMapping defined in class path resource [com/itheima/reggie/config/WebMvcConfig.class]: Failed to instantiate [org.springframework.web.servlet.function.support.RouterFunctionMapping]: Factory met…...
CSS - grid制作表格
1. grid-template-columns:网格布局中的列的数量,也可以设置列的宽度 .grid-container {display: grid;grid-template-columns: 80px 200px auto 40px; }.grid-container {display: grid;grid-template-columns: auto auto auto auto;//表示所有列的宽度…...
【pip】 的换源(临时换源和永久换源)
【pip】 的换源(临时换源和永久换源) 一、临时换源二、永久换源三、Linux换源四、Windows换源 一、临时换源 临时换源只需要在pip安装包时,加上一个-i参数后接源的url即可: 临时换源: 清华源 pip3 install markdown…...
Kaggle 数据集dogs-vs-cats的错误
如果你想用kaggle数据集dogs-vs-cats做深度学习数据,可能会遇到数据bug,大概类似于下面的错误: UnidentifiedImageError: cannot identify image file 其原因不是你的程序有问题,而是数据集本身还有bug: cats/666.jpgdogs/11702.jpg 预览一下…...
【网络原理】网络地址转换----NAT技术详解
💐个人主页:初晴~ 📚相关专栏:计算机网络那些事 我们在 IP协议 一文中介绍过,由于IPv4协议中 IP地址只有32位,导致最多只能表示 42亿9千万个IP地址。但我们需要通过IP地址来标识网络上的每一个设备&#x…...
React怎么创建虚拟dom和挂载到页面
1、🍟你可以直接下载本节配套的资源代码,然后导入vscode看效果,也可以跟着教程一点一点敲,都是没问题的。 2、🤔怎么运行本节代码? 很简单,随便找个浏览器打开index.html即可。💕 代…...
kafka-console-ui的简介及安装使用
kafka-console-ui的简介及安装使用 一、kafka-console-ui的简介二、安装kafka-console-ui2.1 源码安装2.2 docker安装 三、kafka-console-ui功能使用3.1、功能特性3.2、 功能介绍3.2.1 集群3.2.2 topic3.2.3 消费组3.2.4 Acl3.2.5 运维 一、kafka-console-ui的简介 kafka-cons…...
git 的分支管理详解
Git 的分支管理是其强大功能之一,允许开发者在同一代码库中并行开发多个特性或修复 bug,而不干扰主分支的代码。下面是对 Git 分支管理的详解: 1. 查看分支 查看所有分支 git branch # 查看本地分支 git branch -r # 查看远程分支 git br…...
w003基于Springboot的图书个性化推荐系统的设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
医院信息化与智能化系统(6)
医院信息化与智能化系统(6) 这里只描述对应过程,和可能遇到的问题及解决办法以及对应的参考链接,并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图,可以试试PlantUML,告诉GPT你的文件结构,让他给你对应的…...
前端学习---(6)js基础--4
Promise Promise 是异步编程的一种新的解决方案和规范。 Promise优点: 1、可以很好地解决ES5中的回调地狱的问题(避免了层层嵌套的回调函数)。 2、统一规范、语法简洁、可读性和和可维护性强。 3、Promise 对象提供了简洁的 API,使得管理异步…...
241026-RHEL如何以root身份卸载Docker
在 RHEL 8.8 中,以 root 身份卸载 Docker 可以通过以下步骤完成: 停止 Docker 服务(如果已启动): sudo systemctl stop docker删除 Docker 包: 运行以下命令卸载 Docker 引擎及其依赖包(docker-…...
iPhone当U盘使用的方法 - iTunes共享文件夹无法复制到电脑怎么办 - 如何100%写入读出
效果图 从iPhone复制文件夹到windows电脑 步骤windows 打开iTunes通过USB连接iPhone和电脑手机允许授权iTunes中点击手机图标,进入到点击左边“文件共享”,在右边随便选择一个App(随意...)写入U盘:拖动电脑的文件&am…...
jenkins ssh 免密报错Host key verification failed.
jenkins 发布项目,ssh连接远程服务器时报错:Host key verification failed. 解决: 原因是生成的sshkey不是用的jenkins用户,所以切换用户到:jenkins重新生成sshkey su jenkins ssh-keygen -t rsa ssh-copy-id -i ~/…...
智能科学与技术(一级学科)介绍
智能科学与技术:探索智能的边界与未来 智能科学与技术的起源与发展学科定位与内涵学科范围与研究方向培养目标相关学科 在当今这个信息爆炸的时代,人工智能(AI)已经成为科技创新的重要驱动力。随着技术的不断进步,智能…...
iOS调试真机出现的 “__llvm_profile_initialize“ 错误
一、错误形式: app启动就崩溃,如下: Demo__llvm_profile_initialize:0x1045f7ab0 <0>: stp x20, x19, [sp, #-0x20]!0x1045f7ab4 <4>: stp x29, x30, [sp, #0x10]0x1045f7ab8 <8>: add x29, sp, #0x100x1…...
Android SELinux——neverallow问题处理(十六)
上一篇我们介绍了通过添加允许策略处理问题,这里我们主要来看一些 neverallow 策略问题该怎么处理。 一、neverallow介绍 遇到 neverallow 规则问题,千万别急着去注释/剔除里面原有的规则(原生的尽量别动)。增加 allow 规则是常见的解决办法,但是随着 android 版本的升级…...
Vue 关于路由
关于路由 路由的模式与区别 路由的两种模式: hashhistory 区别: 表象不同 hash 模式中,在地址里以 /#/ 分隔;history 模式中,地址里以 / 分隔。关于找不到当前页面发送请求的问题 history 模式会给后端发送一次请…...
推荐做幻灯片搜图网站/seo是什么服务
盘点 GitHub 上那些神级指南!本次盘点都是 GitHub 上标星 10K 的开源指南。都是由中国的开发者开源,除了技术、教程类的指南,还有一些花里胡哨的东西。本期推荐开源项目目录:1. 计算机自学指南2. 大数据入门指南3. 程序员延寿指南…...
关于网站建设的大学/关键词网络推广企业
请简述赋值, 深拷贝和浅拷贝的区别?(python中如何拷贝一个对象?)直接赋值(li1 li): 只传递对象的引用, li1指向对象li的内存地址空间,因此, 原有列表li改变, 被赋值的li1也会做相应的改变.浅拷贝:li和li2的内存地址不同,但是子…...
网站流量数据分析/吸引客人的产品宣传句子
查了一些资料也不是太明白两个的区别,但是前者是最安全的用法 打个简单的比方,你一个WEB程序,发布到Tomcat里面运行。首先是执行Tomcat org.apache.catalina.startup.Bootstrap类,这时候的类加载器是ClassLoader.getSystemClassLo…...
芜湖哪里有做网站的/网页推广方案
2019独角兽企业重金招聘Python工程师标准>>> 时间轴组合-Timeline Portfolio 转载于:https://my.oschina.net/GaoLNMP/blog/207530...
wordpress设置缓存/淘宝运营培训班学费大概多少
我们以Android获取TP报点为例,分析poll过程。poll系统调用功能是检测设备是否有可读等对应事件发生时,调用read系统调用实现对设备的无阻塞访问。现在我们来分析poll的基本调用流程。 首先看应用如何使用poll: int main(int argc, char* argv[]) {int …...
分享社交电商十大平台/西安seo优化
点击上方“Java基基”,选择“设为星标”做积极的人,而不是积极废人!每天 14:00 更新文章,每天掉亿点点头发...源码精品专栏 原创 | Java 2021 超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框…...