图(邻接矩阵)知识大杂烩!!(邻接矩阵结构,深搜,广搜,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…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...

实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...