图(邻接矩阵)知识大杂烩!!(邻接矩阵结构,深搜,广搜,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…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
