【数据结构】图论(图的储存方式,图的遍历算法DFS和BFS、图的遍历算法的应用、图的连通性问题)

本文主要是介绍【数据结构】图论(图的储存方式,图的遍历算法DFS和BFS、图的遍历算法的应用、图的连通性问题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 图论
    • 一、 图的基本概念和术语
    • 二、图的存储结构
      • 1. 数组(邻接矩阵)存储表示
        • 无向图的数组(邻接矩阵)存储表示
        • 有向图的数组(邻接矩阵)存储表示
      • 邻接表存储表示
      • 有向图的十字链表存储表示
      • 无向图的邻接多重表存储表示
    • 三、图的遍历算法
      • 图的遍历——深度优先搜索(DFS)
      • 图的遍历——广度优先搜索(BFS)
    • 四、图的遍历算法的应用(无向图)
    • 五、图的连通性问题
      • 生成树
      • Prim算法
      • Kruskal 算法

图论

一、 图的基本概念和术语

网状结构,逻辑关系多对多

  1. :图G由集合V和E组成,记为G=(V,E)。图中的结点称为顶点,V(G)是顶点的非空有穷集;相关的顶点偶对称为边,E(G)是边的有穷集。

图分为有向图、无向图

  1. 有向图(Digraph)——V(G)是顶点的非空有限集;E(G)是有向边(即弧)的有限集合,弧是顶点的有序对,记<v, w>,v为弧尾(Tail),w为弧头(Head)
  2. 无向图(Undigraph)——V(G)是顶点的非空有限集;E(G)是边的有限集合,边是顶点的无序对,记(v, w)或(w, v),并且(v, w)=(w, v).
    在这里插入图片描述
  1. 顶点:表示数据元素

  2. :表示数据元素之间的逻辑关系,分为有向边(顶点的有序对)和无向边(顶点的无序对)

  3. :边带权的无向图称作无向网;弧带权的有向图称作有向网。

  4. 完全图:n个顶点的含有 n(n-1)/2 条边的无向图称作完全图;n个顶点的含有 e=n(n-1) 条弧的有向图称作 有向完全图.
    若边或弧的个数 e<nlogn,则称作稀疏图,否则称作稠密图。

  5. 邻接点、关联:假若顶点v 和顶点w 之间存在一条边,则称顶点v 和w 互为邻接点,边(v,w)和顶点v 和w相关联

  6. :无向图中和顶点v 关联的边的数目定义为v的度,记为TD(v)
    有向图顶点的度分为入度出度
    入度:有向图中以顶点v为弧头的弧的数目称为顶点v的入度,记为ID(v)
    出度:有向图中以顶点v为弧尾的弧的数目称为顶点v的出
    度,记为OD(v)

  7. 路径、路径长度:设无向图G=(V,E)中的一个顶点序列 u = v i , 0 , v i , 1 , … , v i , m = w { u=v_i,₀,v_i,₁, …, v_i, m=w} u=vi,0,vi,1,,vi,m=w中,若 ( v i , j − 1 , v i , j ) ∈ E , 1 ≤ j ≤ m (v_{i, j-1},v_{i, j})∈E,1 ≤ j ≤ m (vi,j1,vi,j)E1jm,则称从顶点u 到顶点w 之间存在一条路径;路径上边的数目称作路径长度
    简单路径:序列中顶点不重复出现的路径
    简单回路:序列中第一个顶点和最后一个顶点相同的路径

  8. 连通图:若无向图G中任意两个顶点之间都有路径相通,则称此图为连通图。

  9. 连通分量:若无向图为非连通图,则图中各个极大连通子图称作此图的连通分量。

在这里插入图片描述

  1. 强连通图:有向图中若任意两个顶点之间都存在一条有向路径,则称此有向图为强连通图。否则,其各个极大强连通子图称作它的强连通分量。
    在这里插入图片描述

  2. 生成树:假设一个连通图有 n 个顶点和 e 条边,其中 n-1 条边和 n 个顶点构成一个极小连通子图,称该极小连通子图为此连通图的生成树。

  3. 生成森林:对非连通图,则称由各个连通分量的生成树的集合为此非连通图的生成森林。
    在这里插入图片描述

  4. 有向树:如果一个有向图恰有1个顶点的入度为0,其余的顶点入度均为1,则称该图为一棵有向树

  1. 对于非强连通图的一个强连通分量:包含其全部n个顶点、n-1条弧、且只有1个顶点的入度为0、其余的顶点入度均为1的子图称为该连通分量的有生成向树.
  2. 对于非强连通图的所有强连通分量的有向生成树构成该有向图的生成森林.
  3. 一个有向图的生成森林由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧.

二、图的存储结构

■ 图的存储表示(非顺序存储映像):

  1. 图的数组(邻接矩阵)存储表示
  2. 图的邻接表存储表示
  3. 有向图的十字链表存储表示
  4. 无向图的邻接多重表存储表示

■ 设计图的存储表示,应考虑方便以下操作:
• 求入度,出度
• 求邻接顶点
• 判断顶点之间是否有边相连

1. 数组(邻接矩阵)存储表示

无向图的数组(邻接矩阵)存储表示

■ n个顶点的图用2个数组存放:二维数组( n ∗ n n*n nn的矩阵)存放顶点之间的逻辑关系(图中的边、弧),一维数组存放顶点信息(数据元素的
■ 设无向图 G = ( V , E ) G=(V,E) G=(V,E),A[i][j]表示顶点 v i v_i vi v j v_j vj之间是否存在连边
在这里插入图片描述
可以利用对称阵的压缩存储方法存储

无向图顶点 v i v_i vi的度
在这里插入图片描述

有向图的数组(邻接矩阵)存储表示

设有向图 G = ( V , E ) G=(V,E) G=(V,E), A[i][j]表示是否存在顶点 v i v_i vi流向顶点 v j v_j vj的弧.
在这里插入图片描述

有向图邻接矩阵不一定是对称阵
在这里插入图片描述

无向网的邻接矩阵 w i j w_{ij} wij表示在顶点 v i v_i vi v j v_j vj的连边上的权值。 在这里插入图片描述
有时:也用 ∞ ∞ 代表没有边

有向网的邻接矩阵 w i j w_{ij} wij表示在顶点 v i v_i vi流向顶点 v j v_j vj的弧上的权值. 在这里插入图片描述

#define MAXSIZE 100
typedef struct {VertexType    vexs[MAXSIZE]; //一维数组存放顶点信息 int  arcs[MAXSIZE][MAXSIZE];//邻接矩阵int  vexnum, arcnum; //顶点数和边数int kind; //图的类型:有向图还是无向图
} MGraph;
MGraph T;

在这里插入图片描述

邻接表存储表示

无向图的邻接表:为顶点vi所建的单链表是将与顶点vi相关联 的边建成一个单链表;或者说:将顶点vi的邻接点建成一个单链表。

■ 图的一种链式存储结构,对图中每个顶点建立一个单链表,为顶
v i v_i vi所建的单链表是将与顶点 v i v_i vi相关联的边或弧建成一个单链表。
■ 用一维数组存放每个顶点的信息和相应单链表的头指针。
■ 每个数组元素存放图中一个顶点:顶点的数据(data)和为其所建单链表的头指针(firstarc)。

在这里插入图片描述

为便于维护数据的一致性,通常单链表中只要给出邻接点的存放位置----在一维数组中对应数组元素的下标即可

存的边数是2e个 ,也就是每个弧存了2次
在这里插入图片描述
有向图的邻接表:第i个单链表(为 v i v_i vi所建单链表)中的结点是从顶点 v i v_i vi流出的弧流向的顶点
顶点vi的出度是第i个单链表中含有的数据元素的个数,即为vi所建单链表的长度。
在有向图的邻接表中不易找到指向该顶点的弧。
在这里插入图片描述

typedef struct ArcNode {int vex;  // 该弧所指向的顶点的位置 struct ArcNode *link; // 指向下一条弧的指针 InfoType  *info;  // 该弧相关信息的指针
}ArcNode;//单链表节点类型typedef struct VNode {int data; // 顶点信息ArcNode *firstarc; // 指向第一条依附该顶点的弧
}VNode;//数组元素类型typedef struct {VNode  arc[MAXSIZE]; int   vexnum, arcnum;int  kind; //表示有向图还是无向图
}Graphs;

逆向:
有向图的逆邻接表中,为顶点vi建的单链表示流向该顶点的弧
在这里插入图片描述
在这里插入图片描述

网的邻接表表示
在这里插入图片描述

有向图的十字链表存储表示

每个顶点建2个单链表:流出去的弧建一个单链表,流入的弧建一个单链表。
在这里插入图片描述

typedef structArcBox { // 弧的结构表示int tailvex, headvex; InfoType *info;//注意定义的类型struct ArcBox *hlink,*tlink;
}ArcBox;typedef structVexNode { // 顶点的结构表示int data;ArcBox *firstin,*firstout;
}VexNode;typedef struct {VexNode xlist[MAXSIZE]; // 顶点信息int vexnum, arcnum; //有向图的当前顶点数和弧数
}OLGraph;

在这里插入图片描述

无向图的邻接多重表存储表示

在这里插入图片描述

边的结构表示

typedef struct Ebox {int   mark;int   ivex, jvex;struct EBox *ilink, *jlink;
} EBox;

三、图的遍历算法

图的遍历:从图中某个顶点出发访遍图中其余顶
点,并且使图中的每个顶点仅被访问一次的过程

遍历应用举例:

  • 判断图的连通性、
  • 求等价类等
  • 求连通分量
  • 求路径相通

深度优先搜索广度优先搜索

图的遍历——深度优先搜索(DFS)

  1. 图的存储——邻接矩阵和邻接表均可以
  2. 判别图中的顶点v的邻接点是否被访问的方法:
    ⮚ 解决的办法:为每个顶点设立一个“访问标志”,设一维数组visited[ ]
    ① visited[v]=1表示顶点v已经被访问
    ② visited[v]=0表示顶点v尚未被访问
    ③ 初始化时,所有顶点均为未被访问
  • 深度优先搜索生成树:访问时经过的顶点和边构成 的子图
  • 深度优先搜索生成森林:若选用多个出发点做深度优先搜索,会产生多棵深度优先搜索生成树—构成深度优先搜索生成森林.

深度优先搜索遍历连通图的过程类似于树的先根遍历`

深度优先搜索应用
判断无向图是否连通?
若从无向图中任一点出发能访问到图中所
有顶点,则该图为连通图
判断有向图是否强连通?
若从有向图中每一点出发能访问到图中所有顶点,则该图为强连通图.

实现方法:
邻接表为例实现图的深度优先搜索
存储结构为:

typedef struct ArcNode {int vex;  // 该弧所指向的顶点的位置 struct ArcNode *link; // 指向下一条弧的指针 InfoType  *info;  // 该弧相关信息的指针
} ArcNode;//单链表节点类型typedef struct VNode {int data; // 顶点信息ArcNode *firstarc; // 指向第一条依附该顶点的弧
} VNode;//数组元素类型typedef struct {VNode  arc[MAXSIZE]; int   vexnum, arcnum;int  kind; //表示有向图还是无向图
} Graphs;

DFS实现流程图以及代码:
在这里插入图片描述

typedef struct ArcNode {int vex;  // 该弧所指向的顶点的位置 struct ArcNode *link; // 指向下一条弧的指针 InfoType  *info;  // 该弧相关信息的指针
} ArcNode;//单链表节点类型typedef struct VNode {int data; // 顶点信息ArcNode *firstarc; // 指向第一条依附该顶点的弧
} VNode;//数组元素类型typedef struct {VNode  arc[MAXSIZE]; int   vexnum, arcnum;int  kind; //表示有向图还是无向图
} Graphs;//深度优先搜索
void DFSTraverse(Graphs G){for(int v=0;v<G.vexnum;++v){visited[v]=0;for(v=0;v<G.vexnum;++v){if(!visited[v])DFS(G,v);}}}void DFS(Graphs G,int v){printf("%d\t",v);visited[v]=1;p=G.arc[v].firstarc;while(p){w=p->vex;if(visited[w]==0)DFS(G,w);p=p->link;}
}

在这里插入图片描述

图的遍历——广度优先搜索(BFS)

■ 广度优先搜索生成树:访问时经过的顶点和边构成的子图。
■ 广度优先搜索生成森林:选用多个出发点做广度优先搜索,会产生多棵广度优先搜索生成树—构成广度优先搜索生成森林。
■ 对连通图,从起始点v到其余各顶点必定存在路径。按此路径长度递增次序访问。

在这里插入图片描述

int visited[Max];
void BFSTraverse(Graphs G){   for(v=0; v<G.vexnum; ++v) visited[v] = 0;for( v=0; v<G.vexnum; ++v ) if(!visited[v]) BFS(G, v);
}void BFS(Graphs G,int v){int Q[MAX],f=0,r=0;printf("%d\t",w);visited[v]=1;Q[r++]=v;while(f<r){x=Q[f++];p=G.arc[x].firstarc;while(p){w=p->vex;if(visited[w]==0){visited[w]=1;printf("%d\t",w);Q[r++]=w;}p=p->link;}}
}

最小生成树

四、图的遍历算法的应用(无向图)

(待补充)
求两个点之间的最短路径
求两个顶点之间的简单路径
直接使用深度优先搜索还不太行 需要先处理一下
遍历应用举例:

  • 判断图的连通性、
  • 求等价类等
  • 求连通分量
  • 求路径相通

五、图的连通性问题

生成树的存放方式:

  1. 孩子兄弟表示法
  2. 双亲表示法

⮚ 若从无向图中任一点出发采用深度优先搜索或广度优先搜索能访问到图中所有顶点,则该图为连通图,否则为非连通图

对连通图:深度优先搜索或广度优先搜索访问时经过的顶点和边构成的子图称为深度优先搜索生成树或广度优先搜索生成树

对非连通图:深度优先搜索或广度优先搜索访问时经过的顶点和边构成的子图称为深度优先搜索生成森林或广度优先搜索生成森林

生成树

生成树 子图 连通的子图
■ 生成树:假设一个连通图有 n 个顶点和 e 条边,其中 n-1
条边和 n 个顶点构成一个极小连通子图,称该极小连通子图为此连通图的生成树。

生成森林:对非连通图,则称由各个连通分量的生成树的集合为此非连通图的生成森林。

最小生成树 带权图的生成树上的各边权值之和 称为这棵树的代价。最小代价生成树是各边权值总和最小的生成树

最小生成树的性质(MST性质) 采用深度优先搜索 或 广度优先搜索 求? 不太行

贪心策略 不一定是最优解 但在生成最小生成树的时候 是适用的 Prim普利姆算法 Kruscal算法

具有MST性质 就是最小生成树

MST性质(最小生成树性质): 令G=(V, E,
W)为一个带权连通图,T为G的一生成树。对任一不在T中的边uv,如果将uv加入T中会产生一回路,使得uv是回路中权值最大的边。那么树T具有MST性质。

Prim算法

图采用邻接矩阵邻接表存放均可。下面以邻接矩阵为例实现prim算法

define MAX 100
define MAXEDGE 1000000
typedef struct{int arcs[MAX][MAX];int vexnum,arcnum;
}AGraphs;

Prim算法代码示例:

define MAX 100
define MAXEDGE 1000000
typedef struct{int arcs[MAX][MAX];int vexnum,arcnum;
}AGraphs;typedef struct{int adjvex;int lowcost;
}EdgeType;
/*当顶点v尚未加入生成树时,closedge[v]存放的是v与生成树中的顶点相连的最好情况:v与生成树中的顶点的所有连边中权值最小的那条边;closedge[v].adjvex存放的这条权值最小的边的另一个顶点,closedge[v].lowcost存放的这条权值最小的边的权值如何区分生成树中的顶点和不在生成树中的顶点呢?closedge[w].lowcost==0表示w已经加入生成树
*/
void prim(AGraphs G,int u){int i,j,k;EdgeType closedge[MAX];for(j=0;j<G.vexnum;j++){	closedge[j].adjvex=u;closedge[j].lowcost=G.arcs[u][j];} closedge[u].lowcost=0;for(i=1;i<G.vexnum;i++){ k=minclosedge(closedge); printf("(%d,%d)", closedge[k].adjvex,k);closedge[k].lowcost=0; for(j=0;j<G.venum;j++)if(G.arcs[k][j]< closedge[j].lowcost){ closedge[j].lowcost= G.arcs[k][j]; closedge[j].adjvex =k;}}
}int minclosedge(EdgeType closedge[]){int min,j,k; min=MAXEDGE; k=-1;for(j=0;j<G.vexnum;j++)if(closedge[j]. lowcost !=0&&closedge[j].lowcost<min){min=closedge[j]. lowcost; k=j;}return k;
}
//时间复杂度:O(n2) Prim算法适合于稠密图

问法
最小生成树的求解过程
文字叙述 画表 求解过程
伪码描述(上述程序)

Kruskal 算法

先排序
对所有边按照权值升序排序
从小开始加 只要不产生回路
最后加到 n − 1 n-1 n1
需要 排序(适合于吸收图)

Kruscal算法适合稀疏图,时间复杂度为O(eloge),e为图的边数,因为该算法要对边按照权值排序,(堆、快速。归并)排序算法的平均时间复杂度O(eloge)

这篇关于【数据结构】图论(图的储存方式,图的遍历算法DFS和BFS、图的遍历算法的应用、图的连通性问题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/919847

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in