图的概念、存储与遍历

news/2024/10/12 14:20:25

相关概念

图 (graph) 是一个二元组 \(G=(V(G),E(G))\)。其中 \(V(G)\) 是非空集,称为 点集 (vertex set),对于 \(V\) 中的每个元素,我们称其为 顶点 (vertex)节点 (node),简称 \(E(G)\)\(V(G)\) 结点之间边的集合,称为 边集 (edge set)

​ —— OI-Wiki

与树类似,同样使用结点和边来组织一张图,图上的一条边表示两个结点之间有关联。

但与树不同的是,图虽然也由顶点和边构成,但是它没有父亲和儿子的关系,任意两点之间的路径也可能并不唯一。

图可大致分为两种图, 无向图 (undirected graph)有向图 (directed graph)混合图 (mixed graph) 可分为有部分双向边的有向图。

无向图中,如果有一条边连接 \(u\)\(v\),则 \(u\) 可到 \(v\)\(v\) 也可到 \(u\)

有向图中,如果有一条边表示从 \(u\)\(v\),则 \(u\) 可到 \(v\),但 \(v\) 不可到 \(u\)

图的概念很多,这里只写了较为重要的概念,详细的概念可见 图论相关概念 - OI Wiki。

带权图

从一张图的边进行分类,边上有权值的图称为 带权图,没有则称为 无权图

简单图

如果一张图的任意两点之间,只含有最多一条边,即 重边,同时,不存在连接自己到自己的边,即 自环,那么这种图就叫做简单图。如果一张图允许存在自环和重边,那么这张图就不是简单图。

稠密图与稀疏图

对于无向图,我们知道 \(n\) 个顶点的无向图最多只有 \(\frac{n(n-1)}{2}\) 条边,对于有向图,最多有 \(n(n-1)\) 条边。对于一张简单图,它的边数几乎达到 \(O(n^2)\) 的图称为稠密图,边数差不多为 \(O(n)\) 的图称为稀疏图。

对于一张有向图中的一个结点 \(v\), 可直接到达 \(v\) 的结点数量称为 入度(in-degree),从 \(v\) 出发到达的结点数量称为 出度(out-degree)。如下图,\(1\) 的入度是 \(1\),出度是 \(2\)\(4\) 的入度是 \(2\),出度是 \(0\)

而对于一张无向图中的一个结点 \(v\),则只有 度(degree) 一说,结点 \(v\)度(degree) 就是与顶点 \(v\) 相关联的结点的数量。如下图,\(1\) 的度是 \(3\)\(4\) 的度是 \(2\)

image

连通

如果两个结点可通过一条路径互相到达,我们称之为这两个结点连通。

对于无向图,任意 两个结点都可以互相到达,那么我们叫这张图为连通图,反之则称为非连通图。

对于有向图,两个结点它们之间可以互相到达,我们称这两个结点为强连通,如果一个有向图上任意两个结点都可以互相到达,我们叫这张图为强连通图。

子图

我们取出一张图其中的一些顶点,以及保留两端都在这些顶点之中的边,这样构成的子图称为 顶点导出子图

我们取出这张图的一些边,并保留这些边的顶点,这样构成的子图为边导出子图。


存储

邻接矩阵

邻接矩阵适用于稠密图,我们可以定义一个二维数组 \(g[][]\),对于 \(u\)\(v\) 两个结点,我们可以用 \(g[u][v]\) 来表示这两个点有一条边,如果是带权图,则可以记录这条边的权值,构造的空间复杂度是 \(O(n^2)\),但查询两个结点的时间复杂度只有 \(O(1)\)

\(\texttt{code}\)

int g[MAXN][MAXN];
......
for(int i=1;i<=m;i++){int u,v;cin>>u>>v;g[u][v]=1;//如果是无向图,这里应该是 g[u][v]=g[v][u]=1
}

邻接表

邻接表主要适用于稀疏图,我们定义 \(n\) 个向量,用于存储结点 \(u\) 可以直接到达的所有结点,如果是带权图,可以开一个结构体 node,含有二维信息 tow,分别表示到达的顶点和这两个点之间的边权,当然也可以用 pair 来记录这两个值,空间复杂度 \(O(m)\),但是判断两个结点是否有连边,需要遍历整个 vector 查询,最坏时间复杂度 \(O(n)\)

\(\texttt{code}\)

vector<int> g[MAXN];
......
for(int i=1;i<=m;i++){int u,v;cin>>u>>v;g[u].push_back(v);g[v].push_back(u);//无向图
}
//1struct node{int to,w;
}
vector<node> g[MAXN];
......
for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;g[u].push_back((node){v,w});g[v].push_back((node){u,w});
}
//2vector<pair<int,int>> g[MAXN];
......
for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;g[u].push_back(make_pair(v,w));g[v].push_back(make_pair(u,w));
}
//3

存边

除了以上两种存点的方式,还可以用结构体存储一条边,结构体中的成员变量 frtow,分别表示这条边所连接的两个结点和这条边的边权,空间复杂度 \(O(m)\)

struct Edge{int fr,to,w;
}edges[MAXN];

遍历

图的 bfs 遍历:

\(\texttt{code}\)

vector<int> g[MAXN];
void bfs(int s){queue<int> q;q.push(s);vis[s]=1;while(!q.empty()){int now=q.front();cout<<now<<" ";q.pop();for(auto x:g[now]){if(vis[x]==0){vis[x]=1;q.push(x);}}}
}

图的 dfs 遍历:

\(\texttt{code}\)

vector<int> g[MAXN];
void dfs(int now){cout<<now<<" ";vis[now]=1;for(auto x:g[now]){if(vis[x]==0){dfs(x);}}
}

以上两种写法的时间复杂度是 \(O(n+m)\)

拓扑排序

对于一个有向无环图,有一个遍历顺序,是等一个结点的所有前驱结点都遍历完了,才遍历这个结点。这种顺序就叫做拓扑序。

对于下面这张图,它的拓扑序可以是 1 2 3 4 5,而 1 2 4 3 5 则不是,因为 \(4\) 的前驱还有 \(3\) 没有遍历,必须先遍历 \(3\) 才能遍历 \(4\)

int in[MAXN],res[MAXN];
vector<int> g[MAXN];
int num;
int topo(){for(int i=1;i<=n;i++){for(auto x:g[i]){in[x]++;}}queue<int> q;for(int i=1;i<=n;i++){if(in[i]==0){ q.push(i);}}while(!q.empty()){int k=q.front();q.pop();res[++num]=k;for(auto x:g[k]){in[x]--;if(in[x]==0){q.push(x);}}}if(num!=n){return false;}else{ return true;}
}

时间复杂度 \(O(n+m)\)

欧拉路径问题

给你一个图,请你选择一个起点出发,经过所有的边,要求每条边只能经过一次,问能否达成目标,也称一笔画问题。

欧拉定理:如果一张连通图,只有 \(0\) 个或者 \(2\) 个结点,他的度为奇数,那么这张图可以一笔画。

证明:我们选择一个度数为奇数的顶点出发,走向一个度数为偶数的顶点,那么这个图变成了一个仍然满足上述性质但是结构更简单的图了。所以我们可以归纳证明上述定理。

对于这道题,我们可以使用 Hierholzer算法,它的思路是,对于欧拉回路,我相当于是将图拆成若干个环。所以我每次找图的正好一个环,如果没法找了,我就回溯地把这个环给存起来,存到栈中。

\(\texttt{code}\)

vector<pair<int,int>> g[MAXN];
stack<int> s;
int vis[maxm];//对边标记
void dfs(int now){for(auto x:g[now]){if(vis[x.second]==0){vis[x.second]=1;dfs(x.first);}}s.push(now);
}

时间复杂度 \(O(n+m)\)

画图网站推荐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/27244.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

基于SSM的仓库进销存系统毕业设计论文【范文】

摘要 随着信息技术的不断发展,企业对于仓储管理的要求日益提高。为了提升仓库管理的自动化和智能化水平,本研究设计并实现了一个基于Spring、Spring MVC和MyBatis (SSM) 框架的在仓库进销存系统。该系统旨在为企业提供一个高效、准确、实时的库存管理解决方案,以优化库存控制…

FreeRTOS任务通知

FreeRTOS任务通知 FreeRTOS 新增了任务通知(Task Notifictions)这个功能,可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高,任务通知在 FreeRTOS 中是一个可选的功能, 使用队列、信号量、事件标志组时都需另外创建一个结构体,通…

uboot-学习笔记

uboot引导程序的作用不同bootloader的对比系统启动自举过程阶段

【软件构造课程相关】幻方及其构造(上)

介绍 ​ 幻方(Magic Square),有时又称魔术方阵或纵横图,由一组排放在正方形中的整数组成,其每行、每列以及每一条主对角线的和均相等。通常幻方由从1到$N2$的连续整数组成,其中N为正方形的行或列的数目。因此N阶幻方有N行N列,并且所填充的数为从1到$N2$。 ​ …

SDL库基础学习

初始化 int SDL_Init(Uint32 flags);* `flags` may be any of the following ORd together:** - `SDL_INIT_TIMER`: timer subsystem* - `SDL_INIT_AUDIO`: audio subsystem* - `SDL_INIT_VIDEO`: video subsystem; automatically initializes the events* subsystem* - `SDL…

2024-5-1 假期第一天 愉快

假期第一天,中午十点多醒的,经过一番挣扎之后还是下定决心去本部开点二硫化硒,于是坐地铁去本部,到了发现皮肤科不开,遂返回,虽然无功而返吗,但是今天天气是真的好,路上骑行看到的风景很美,回来的时候去物美逛了一圈买了点香蕉,买了点饮料,然后又花30买了两杯喜茶,…

WPF上位机 - 使用转换器实现TIA Wincc中的可见性和外观功能

在TIA Wincc 中有这样的功能,使用True or false 控制控件的可见性或者外观的情况。在上位机中需要使用转换器这样对True or false 值转换为 需要的笔刷或者Visible属性。 using System; using System.Collections.Generic; using System.Globalization; using System.Linq; us…

Spring AOP

AOP简介A0P(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构OOP(object Oriented Programming)面向对象编程作用:在不惊动原始设计的基础上为其进行功能增强 Spring理念:无入侵式/无侵入式AOP核心概念连接点(JoinPoint):程序执行过程…