建立一个图

核心问题

  1. 怎么表示结点
  2. 怎么表示边以及边权

邻接矩阵

用二维数组表示一张图:数组的下标表示结点,数组的值表示边权。

如 G[1][2] = 11 表示结点1和2之间有条边且边权为2。

如要表示结点1和3之间没有边,可以写作: G[1][3] = 0/-1/INF。(INF是一个很大的数,一般取100,000,000)

const MAXV = 100; //最大顶点数
int n, G[MAXV][MAXV] = 0; //n为顶点数,MAXV为最大顶点数 int main(){
int n,m; //结点数和边数
int u,v,weight; //边的两端点和边权
scanf("%d%d", &n,&m);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &u,&v,&weight);
G[u][v] = weight;
G[v][u] = weight; //如果是无向图
}
}

邻接表

用一维数组的下标表示结点,且数组的每个元素是一个指针,指向一条链表。故每个结点对应一条链表。

每个结点对应链表中存放着它的邻接点和边权,这样就表示出了每个结点所连接的边。

/*直接应用stl库中的vector实现*/
/*可以直接把vector理解为变长数组,这样免去了链表操作的麻烦*/
#include<stdio.h>
#include<vector>
using namespace std; //调用vector
const int MAXV = 100;//最大结点数
struct Node{
int v; //边的终点编号
int w; //边权
Node(int _v, int _w) : v(_v), w(_w) {} //构造函数
};
vector<Node> Adj[MAXV]; //用邻接表表示的图
int n; int main(){
int n,m; //结点数和边数
int u,v,w; //边的两端点和边权
scanf("%d%d", &n,&m);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &u,&v,&w);
Adj[u].push_back(Node(v,w)); //利用构造函数,省去了构建临时结点的麻烦
Adj[v].push_back(Node(u,w)); //如果是无向图
}
}

深度优先遍历(DFS)

DFS就是一路走到黑

具体步骤:

第一部分:给定结点u,遍历u所在的连通块的所有结点

  1. 访问当前结点u
  2. 遍历u的所有邻接点Vi
  3. 如果邻接点Vi还未被访问过,对Vi重复1.2步骤

第二部分:对图G所有结点进行第一部分的操作,即遍历了图的所有连通分量

伪代码

注: vis:标记数组,如果顶点i已被访问,则vis[i] == true。 初始化为 false

DFS(u){ //访问顶点u
vis[u] = true; //设置u已被访问
for(从u出发能到达的所有顶点v){ //枚举从u出发可以到达的所有顶点v
if vis[v] == false //如果v未被访问
DFS(v); //递归访问v
}
}
DFSTrave(G){ //遍历图G
for(G的所有顶点u) //对G的所有顶点u
if vis[u] == flase; //如果u未被访问
DFS(u); //访问u所在的连通块
}

邻接矩阵实现

#include<stdio.h>
const int MAXV = 100; //最大顶点数
const int INF = 100000000; //设INF为一个很大的数 int n, G[MAXV][MAXV]; //n为顶点数,MAXV为最大顶点数
bool vis[MAXV] = {false}; //标记数组,如果顶点i已被访问,则vis[i] == true。 void DFS(int u, int depth){ //u为当前访问的节点标号,depth为深度
vis[u] = true; // 设置u已被访问
//如果需要对u进行一些操作,可以在这里进行
//线面对所有从u出发能到大的分支点顶点进行枚举
for(int v = 0; v < n; v++){ //对每个顶点v
if(vis[v] == false && G[u][v] != INF){ //v未被访问 且 u可以到达v
DFS(v, depth+1); //访问v,深度+1
}
}
} void DFSTrave(){ //遍历图G
for(int u = 0; u < n; u++){ //对每个顶点u
if(vis[u] == false){ //如果u未被访问
DFS(u, 1); //访问u和u所在的连通块,1表示初始为第一层
}
}
}

邻接表实现

#include<stdio.h>
#include<vector>
using namespace std;
const int MAXV = 100; //最大顶点数
const int INF = 100000000; //设INF为一个很大的数 vector<int> Adj[MAXV]; //图G的邻接表
int n; //顶点数
bool vis[MAXV] = {false}; //标记数组 void DFS(int u, int depth){
vis[u] = true;
//如果需要对u进行一些操作,可以在这里进行
for(int i = 0; i < Adj[u].size(); i++){
int v = Adj[u][i];
if(vis[v] == false){
DFS(v, depth+1);
}
}
} void DFSTrave(){ //遍历图G
for(int u = 0; u < n; u++){ //对每个顶点u
if(vis[u] == false){ //如果u未被访问
DFS(u, 1); //访问u和u所在的连通块,1表示初始为第一层
}
}
}

广度优先遍历(BFS)

BFS就是放射状探索

具体步骤

第一部分:给定结点u,遍历u所在的连通块的所有结点

先将起点u加入队列,设置u为已访问

  1. 取出队首元素u
  2. 将u的所有未被访问的邻接点Vi入队,并设置为已访问
  3. 如果队列非空,重复1.2步骤

第二部分:对图G所有结点进行第一部分的操作,即遍历了图的所有连通分量

伪代码

BFS(u){
queue q;
inq[u] = true;
while(q非空){
去除q的队首元素u进行访问;
for(从u出发可达的所有顶点v)
if(inq[v] == false){
将v入队;
inq[v] = true;
}
}
} BFSTrave(G){ //遍历图G
for(G的所有顶点u) //枚举G所有的顶点u
if(inq[u] == false){ //如果u未曾加入过队列
BFS(u); //遍历u所在的连通块
}
}

邻接矩阵实现

#include<stdio.h>
#include<queue> //直接应用stl中定义的队列queue
using namespace std;
#define MAXV 100
#define INF 100000000 int n, G[MAXV][MAXV]; //图的邻接矩阵表示
bool inq[MAXV] = {false}; //标记数组 void BFS(int u){ //遍历u所在的连通块
queue<int> q; //定义队列u
q.push(u); //将初始点u入队
inq[u] = true; //设置u已加入过队列
while(!q.empty()){ //只要队列非空
int u = q.front(); //取出队首元素
q.pop(); //将队首元素出队 for(int v = 0; v < n; v++){
//如果u的邻接点未加入过队列
if(inq[v] == false && G[u][v] != INF){
q.push(v); //入队
inq[v] = true; //标记
//可以在此处根据题目添加一些操作
}
}
}
} void BFSTrave(){ //遍历图G
for(int u = 0; u < n; u++){ //枚举所有顶点
if(inq[u] == false){ //如果u未曾加入过队列
BFS(u); //遍历u所在的连通块
}
}
}

邻接表实现

#include<stdio.h>
#include<queue>
#include<vector>
using namespace std;
#define MAXV 100 vector<int> Adj[MAXV]; //图的邻接表表示
int n;
bool inq[MAXV] = {false}; //标记数组 void BFS(int u){
queue<int> q;
q.push(u);
inq[u] = true;
while(!q.empty()){
int u = q.front();
q.pop();
//只有下面的遍历部分与邻接矩阵写法不同
for(int i=0; i < Adj[u].size(); i++){
int v = Adj[u][i];
if(inq[v] == false){
q.push(v);
inq[u] = true;
//可以在此处根据题目添加一些操作
}
}
}
} void BFSTrave(){
for(int u = 0; u < n; u++){
if(inq[u] == false){
BFS(u);
}
}
}

DFS,BFS遍历方法总结

  1. 前置准备:图G的实现(邻接数组,邻接表),标记数组vis(初始化为false)
  2. 函数主体:递归实现。分两部分。

    函数a:遍历结点s所在的连通块。

    函数b:对遍历图G结点应用函数a。
  3. 注意:遍历前用vis判断是否已被标记

<数据结构>图的构建与基本遍历方法的更多相关文章

  1. python数据结构与算法——二叉树结构与遍历方法

    先序遍历,中序遍历,后序遍历 ,区别在于三条核心语句的位置 层序遍历  采用队列的遍历操作第一次访问根,在访问根的左孩子,接着访问根的有孩子,然后下一层 自左向右一一访问同层的结点 # 先序遍历 # ...

  2. IplImage的数据结构以及遍历方法

    一般我们需要对图像直接进行操作的时候,需要知道图像存储的数据结构,这要也就知道了它的遍历方式 在opencv2.4.4版本下,IplImage的数据结构如下(貌似在别的版本下差别也不会太大) 其中比较 ...

  3. C#与数据结构--图的遍历

    http://www.cnblogs.com/abatei/archive/2008/06/06/1215114.html 8.2 图的存储结构 图的存储结构除了要存储图中各个顶点的本身的信息外,同时 ...

  4. java 完全二叉树的构建与四种遍历方法

    本来就是基础知识,不能丢的太干净,今天竟然花了那么长的时间才写出来,记一下. 有如下的一颗完全二叉树: 先序遍历结果应该为:1  2  4  5  3  6  7 中序遍历结果应该为:4  2  5 ...

  5. Java ——集合框架 list lambda set map 遍历方法 数据结构

    本节重点思维导图 集合框架 有序无序:元素放入的顺序与取出的顺序是否一致,一致即为有序,不一致即无序. List:允许重复.有序 ArrayList:长度可变的数组,遍历速度快 LinkedList: ...

  6. 数据结构——图的深度优先遍历(邻接矩阵表示+java版本)

    ​1.深度优先遍历(DFS) 图的深度优先遍历本质上是一棵树的前序遍历(即先遍历自身,然后遍历其左子树,再遍历右子树),总之图的深度优先遍历是一个递归的过程. 如下图所示,左图是一个图,右图是图的深度 ...

  7. 知识图谱-生物信息学-医学顶刊论文(Briefings in Bioinformatics-2021):生物信息学中的图表示学习:趋势、方法和应用

    4.(2021.6.24)Briefings-生物信息学中的图表示学习:趋势.方法和应用 论文标题: Graph representation learning in bioinformatics: ...

  8. 数据结构--图 的JAVA实现(上)

    1,摘要: 本系列文章主要学习如何使用JAVA语言以邻接表的方式实现了数据结构---图(Graph),这是第一篇文章,学习如何用JAVA来表示图的顶点.从数据的表示方法来说,有二种表示图的方式:一种是 ...

  9. 数据结构--图 的JAVA实现(下)

    在上一篇文章中记录了如何实现图的邻接表.本文借助上一篇文章实现的邻接表来表示一个有向无环图. 1,概述 图的实现与邻接表的实现最大的不同就是,图的实现需要定义一个数据结构来存储所有的顶点以及能够对图进 ...

随机推荐

  1. C++一元多项式求导

    这个题难度不大但是坑有点多,要考虑的点有几个: 1.测试用例为x 0 这个直接输出 0 0即可. 2.注意空格的输出 3.测试点3我好几次都没过,最后参考了别的答案加以修改才通过. 测试点3没过的代码 ...

  2. 访问网页全过程,用wireshark抓包分析

    用wireshark抓包查看访问网站过程 打开wireshark,打开一个无痕浏览器,输入网址,到网页呈现这一过程,网络数据包传递的消息都会被放在wireshark里.针对这些包,我们可以逐一分析,摸 ...

  3. vue-cli 如何配置assetsPublicPath; vue.config.js如何更改assetsPublicPath配置;

    问题: vue项目完成打包上线的时候遇到静态资源找不到的问题,网上很多解决办法都是基于vue-cli 2.x 来解决的,但从vue-cli 3.0以后,便舍弃了配置文件夹(便没有了config这个文件 ...

  4. linux基础-TCP/IP协议篇

    一.网络TCP/IP层次模型 1.网络层次模型概念介绍:TCP/IP协议就是用于简化OSI层次,以及相关的标准.传输控制协议(tcp/ip)族是相关国防部(DoD)所创建的,主要用来确保数据的完整性及 ...

  5. Ajax异步更新网页(使用jQuery)

    jquery下载链接:https://pan.baidu.com/s/1KWQVpPV-RwhwGeBaXbZdVA 提取码:vn7x 一.页面代码 <!DOCTYPE html> < ...

  6. 在vue3中使用router-link-active遇到的坑

    在使用 router-link-active 设置链接激活时CSS类名时,发现在例如 /member/order 和 /member/order/:id 这两个都包含 /member/order的路由 ...

  7. 关于og4j漏洞修复解决方案及源码编译

    最近log4j爆出重大漏洞,程序员要赶紧修复了!文末提供已经编译好的jar包. 建议最好修复到log4j-2.15.0-rc2版本,临时解决方案还是存在jndi漏洞. 打开log4j官网https:/ ...

  8. HGAME2021 week4 pwn writeup

    第四周只放出两道题,也不是很难. house_of_cosmos 没开pie,并且可以打got表. 在自写的输入函数存在漏洞.当a2==0时,因为时int类型,这里就会存在溢出.菜单题,但是没有输出功 ...

  9. UNCTF2020 pwn题目

    YLBNB 用pwntools直接连接,然后接受就行. 1 from pwn import * 2 3 p = remote('45.158.33.12',8000) 4 context.log_le ...

  10. Docker 安装&卸载

    不同版本可能有差异具体信息查看官网 官网:https://docs.docker.com/engine/install/centos/ #环境准备 #查看环境 uname -r # 系统内核在3.10 ...