文章目录

  • 图的认识
  • 图的概念
    • 无向图
    • 有向图
    • 简单图
    • 完全图
    • 子图
    • 连通、连通图、连通分量
    • 边的权和网
    • 加权图
    • 邻接和关联
    • 路径
    • 简单路径、简单回路
    • 顶点的度、入度和出度
    • 割点(关节点)
    • 桥(割边)
    • 距离
    • 有向树
  • 图的表示
    • 邻接列表
    • 邻接矩阵
  • 图的遍历
    • 深度优先遍历
    • 广度优先遍历
  • 生成树

图的认识

图(Graph)是由顶点和连接顶点的边构成的离散结构。一个图就是一些顶点的集合,这些顶点通过一系列边结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。

注意:线性表可以是空表,树可以是空树,图不可以是空图,图可以没有边,但是至少要有一个顶点。

图是最灵活的数据结构之一,很多问题都可以使用图模型进行建模求解。
树可以说只是图的特例,但树比图复杂很多

注意:顶点有时也称为节点或者交点,边有时也称为链接。

图有各种形状和大小。边可以有权重(weight),即每一条边会被分配一个正数或者负数值。边可以是有方向的。有方向的边意味着是单方面的关系。从顶点 X 到 顶点 Y 的边是将 X 联向 Y,不是将 Y 联向 X。

树和链表,都可以被当成是树,是一种更简单的形式。他们都有顶点(节点)和边(连接)。

图的概念

图是由顶点集合以及顶点间的关系集合组成的一种数据结构。
由顶点 V 集和边 E 集构成,因此图可以表示成 Graph = (V,E)
V是顶点的有穷非空集合;E是顶点之间关系的有穷集合,也叫边集合。
图按照边或弧的多少分稀疏图和稠密图

无向图

无向图:顶点对<x,y>是无序的。
无向边:若顶点Vi到Vj之间的边没有方向,则称这条边为无向边,用无序偶对(Vi,Vj)来表示
无向图顶点的边数叫做度。
无向图中,顶点的度就是与顶点相关联的边的数目,没有入度和出度。

如果图中任意两个顶点时间的边都是无向边,则称该图为无向图:
  
上图是无向图,所以连接顶点A与D的边,可以表示为无序对(A,D),也可以写成(D,A)
对于如上无向图来说,G=(V,{E}) 其中顶点集合V={A,B,C,D};边集合E={(A,B),(B,C),(C,D),(D,A),(A,C)}

完全无向图:若有n个顶点的无向图有n(n-1)/2 条边, 则此图为完全无向图。

有向图

如果任意两个顶点之间都存在边叫完全图,有向的叫有向图。

有向图:具有方向性,顶点 (u,v)之间的关系和顶点 (v,u)之间的关系不同,后者或许不存在。

有向图:顶点对<x,y>是有序的;

有向边:若从顶点Vi到Vj的边有方向,则称这条边为有向边,也称为弧。

用有序偶<Vi,Vj>来表示,Vi称为弧尾,Vj称为弧头。

连接顶点A到D的有向边就是弧,A是弧尾,D是弧头,<A,D>表示弧。注意不能写成<D,A>。
对于如上有向图来说,G=(V,{E})其中顶点集合V={A,B,C,D};弧集合E={<A,D>,<B,A>,<C,A>,<B,C>}

图中顶点之间有邻接点。有向图顶点分为入度和出度。

简单图

若无重复的边或顶点到自身的边则叫简单图。
1)不存在重复边
2)不存在顶点到自身的边
所以上面的有向图和无向图都是简单图。与简单图相对的是多重图,即:两个结点直接边数多于一条,又允许顶点通过同一条边与自己关联。

完全图

无向图中任意两点之间都存在边,称为无向完全图;
有向图中任意两点之间都存在方向向反的两条弧,称为有向完全图
完全有向图:有n个顶点的有向图有n(n-1)条边, 则此图为完全有向图。

子图

若有两个图G=(V,E),G1=(V1,E2),若V1是V的子集且E2是E的子集,称G1是G的子图。

连通、连通图、连通分量

1.连通
在无向图中,两顶点有路径存在,就称为连通的。

2.连通图
若图中任意两顶点都连通,同此图为连通图。
如果对于任意两个顶点都是连通的,则称该图是连通图。
对于有向图,如果图中每一对顶点Vi和Vj是双向连通的,则该图是强连通图。
连通:无向图中每一对不同的顶点之间都有路径。如果这个条件在有向图里也成立,那么是强连通的。如果从顶点v到顶点v’有路径或从顶点v’到顶点v有路径,则称顶点v和顶点v’是连通的。

有向图的连通分支:将有向图的方向忽略后,任何两个顶点之间总是存在路径,则该有向图是弱连通的。有向图的子图是强连通的,且不包含在更大的连通子图中,则可以称为图的强连通分支。

上图, a 、e没有到 { b , c , d } 中的顶点的路径,所以各自是独立的连通分支。因此,上图有三个强连通分支,用集合写出来就是: { { a } , { e } , { b , c , d } }

3.连通分量
无向图中的极大连通子图称为连通分量。

双连通图:不含任何割点的图。

边的权和网

图上的边和弧上带权则称为网
图中每条边上标有某种含义的数值,该数值称为该边的权值。这种图称为带树图,也称作网。

加权图

加权图:与加权图对应的就是无权图,又叫等权图。如果一张图不含权重信息,我们认为边与边之间没有差别。

邻接和关联

邻接(adjacency):邻接是两个顶点之间的一种关系。如果图包含 (u,v),则称顶点v 与顶点u邻接。在无向图中,这也意味着顶点 u 与顶点 v 邻接。

关联(incidence):关联是边和顶点之间的关系。在有向图中,边 (u,v)从顶点 u开始关联到 v,或者相反,从v关联到u。在有向图中,边不一定是对称的,有去无回是完全有可能的。

路径

两顶点之间的路径指顶点之间经过的顶点序列,经过路径上边的数目称为路径长度。若有n个顶点,且边数大于n-1,此图一定有环。

路径(path):依次遍历顶点序列之间的边所形成的轨迹。

路径:非空序列V0 E1 V1 E2 ... Vk称为顶点V0到顶点Vk的一条路径。

树中根节点到任意节点的路径是唯一的,但是图中顶点与顶点之间的路径却不是唯一的。
路径的长度是路径上的边或弧的数目。
无权图的路径长是路径包含的边数。
有权图的路径长要乘以每条边的权。

简单路径、简单回路

简单路径:没有重复顶点的路径称为简单路径。
除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。

:包含相同的顶点两次或者两次以上。上图序列 <1,2,4,3,1>,1出现了两次,当然还有其它的环,比如<1,4,3,1>。

无环图:没有环的图,其中,有向无环图有特殊的名称(DAG(Directed Acyline Graph)

顶点的度、入度和出度

顶点的度为以该顶点为一个端点的边的数目。

对于无向图,顶点的边数为度,度数之和是顶点边数的两倍。
对于有向图,入度是以顶点为终点,出度相反。有向图的全部顶点入度之和等于出度之和且等于边数。顶点的度等于入度与出度之和。

割点(关节点)

割点:如果移除某个顶点将使图或者分支失去连通性,则称该顶点为割点。某些特定的顶点对于保持图或连通分支的连通性有特殊的重要意义。

割点的重要性不言而喻。如果你想要破坏互联网,你就应该找到它的关节点。同样,要防范敌人的攻击,首要保护的也应该是关节点

桥(割边)

桥(割边):和割点类似,删除一条边,就产生比原图更多的连通分支的子图,这条边就称为割边或者桥。

距离

若两顶点存在路径,其中最短路径长度为距离。

有向树

有一个顶点的入度为0,其余顶点的入度均为1的有向图称作有向树。

图的表示

邻接列表

邻接列表:在邻接列表实现中,每一个顶点会存储一个从它这里开始的边的列表。比如,如果顶点A 有一条边到B、C和D,那么A的列表中会有3条边,邻接列表只描述了指向外部的边。A 有一条边到B,但是B没有边到A,所以 A没有出现在B的邻接列表中。

优点:
(1) 便于增加和删除结点。
(2) 便于统计边的数目,按顶点表顺序扫描所有边表可得到边的数目,时间复杂度为O(n+e)。
(3)空间效率高。对于一个具有n个顶点e条边的图G,若图G是无向图,则在邻接表表示中有n个顶点表结点和2n个边表结点。若G是有向图,则在它的邻接表表示或逆邻接表表示中均有n个顶点表结点和e个边表结点。因此,邻接表的空间复杂度为O(n+e)。
缺点:
(1) 不便于判断顶点之间是否有边,要判断vi 和vj之间是否有边,就需扫描第i个边表,最换情况下要耗费O(n)时间。
(2) 不便于计算有向图各个顶点的度。

邻接矩阵

图最常见的表示形式为邻接链表和邻接矩阵

特点:
⑴0表示这两个顶点之间没有边,1表示有边
⑵顶点的度是行内数组之和
⑶求顶点的邻接点,遍历行内元素即可

邻接矩阵,一个存储着边的信息的矩阵,而顶点则用矩阵的下标表示。对于一个邻接矩阵M,如果M(i,j)=1,则说明顶点i和顶点j之间存在一条边,对于无向图来说,M (j ,i) = M (i, j),所以其邻接矩阵是一个对称矩阵;对于有向图来说,则未必是一个对称矩阵。邻接矩阵的对角线元素都为0。下图是一个无向图和对应的邻接矩阵:


需要注意的是,当边上有权值的时候,称之为网图,则邻接矩阵中的元素不再仅是0和1了,邻接矩阵M中的元素定义为:

邻接矩阵:在邻接矩阵实现中,由行和列都表示顶点,由两个顶点所决定的矩阵对应元素表示这里两个顶点是否相连、如果相连这个值表示的是相连边的权重。例如,如果从顶点A到顶点B有一条权重为 5.6 的边,那么矩阵中第A行第B列的位置的元素值应该是5.6:

优点:
(1) 便于判断两个顶点之间是否有 边,即根据A[i][j] = 0或1来判断。
(2) 便于计算各顶点的度。对于无向图,邻接矩阵的第i行元素之和就是顶点i的度。对于有向图,第i行元素之和就是顶点i的出度,第i列元素之和就是顶点i的入度。

缺点:
(1) 不便于增加删除顶点。
(2)空间复杂度高。如果是有向图,n个顶点需要n*n个单元存储边。如果无向图,其邻接矩阵是对称的,所以对规模较大的邻接矩阵可以采用压缩存储的方法,仅存储下三角元素,这样需要n(n-1)/2个单元。无论哪种存储方式,邻接矩阵表示法的空间复杂度均为0(n*n)

区别:

邻接列表在表示稀疏图时非常紧凑而成为了通常的选择,但稀疏图表示时使用邻接矩阵,会浪费很多内存空间,遍历的时候也会增加开销。
如果图是稠密图,可以选择更加方便的邻接矩阵。
还有,顶点之间有多种关系的时候,也不适合使用矩阵。因为表示的时候,矩阵中的每一个元素都会被当作一个表

图的遍历

深度优先遍历

在深度优先搜索中,保存候补节点是栈,栈的性质就是先进后出,即最先进入该栈的候补节点就最后进行搜索。

深度优先遍历,也有称为深度优先搜索(Depth_First_Search),简称DFS。其实,就像是一棵树的前序遍历。
它从图中某个结点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中的所有顶点都被访问到为止。

#include<iostream>
using namespace std;
int n,m,x,y,a[105][105],book[105][105]= {};
int minn = 999999;
void dfs(int starx,int stary,int step) {int nx,ny;if(starx==x&&stary==y) {if(minn > step) {minn = step;}return ;}int next[4][2]= {0,1,0,-1,1,0,-1,0};for(int i=0; i<4; i++) {nx = starx+next[i][0];  ny = stary+next[i][1];if(nx>n||nx<1||ny>m||ny<1)continue;if(a[nx][ny]==0&&book[nx][ny]==0) {book[nx][ny]=1;dfs(nx,ny,step+1);book[nx][ny]=0;}}return ;
}
int main() {cin>>n>>m>>x>>y;for(int i=1; i<=n; i++) {for(int j=1; j<=m; j++) {cin>>a[i][j];}}book[1][1]=1;dfs(1,1,0);cout<<"最小值为=";cout<<minn<<endl;return 0;
}
/*
5 4 4 3
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
*/

邻接矩阵表达方式:

#define MAXVEX  100     //最大顶点数
typedef int Boolean;            //Boolean 是布尔类型,其值是TRUE 或FALSE
Boolean visited[MAXVEX];        //访问标志数组
#define TRUE 1
#define FALSE 0//邻接矩阵的深度优先递归算法
void DFS(Graph g, int i)
{int j;visited[i] = TRUE;printf("%c ", g.vexs[i]);                           //打印顶点,也可以其他操作for(j = 0; j < g.numVertexes; j++){if(g.arc[i][j] == 1 && !visited[j]){DFS(g, j);                  //对为访问的邻接顶点递归调用}}
}//邻接矩阵的深度遍历操作
void DFSTraverse(Graph g)
{int i;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;         //初始化所有顶点状态都是未访问过状态}for(i = 0; i < g.numVertexes; i++){if(!visited[i])             //对未访问的顶点调用DFS,若是连通图,只会执行一次{DFS(g,i);}}
}

邻接表存储结构:

//邻接表的深度递归算法
void DFS(GraphList g, int i)
{EdgeNode *p;visited[i] = TRUE;printf("%c ", g->adjList[i].data);   //打印顶点,也可以其他操作p = g->adjList[i].firstedge;while(p){if(!visited[p->adjvex]){DFS(g, p->adjvex);           //对访问的邻接顶点递归调用}p = p->next;}
}//邻接表的深度遍历操作
void DFSTraverse(GraphList g)
{int i;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;}for(i = 0; i < g.numVertexes; i++){if(!visited[i]){DFS(g, i);}}
}

对比两个不同的存储结构的深度优先遍历算法,对于n个顶点e条边的图来说,邻接矩阵由于是二维数组,要查找某个顶点的邻接点需要访问矩阵中的所有元素,因为需要O(n2)的时间。而邻接表做存储结构时,找邻接点所需的时间取决于顶点和边的数量,所以是O(n+e)。显然对于点多边少的稀疏图来说,邻接表结构使得算法在时间效率上大大提高。

广度优先遍历

广度优先搜索和深度优先搜索一样,都是对图进行搜索的算法,都是从起点开始顺着边搜索,此时并不知道图的整体结构,直到找到指定节点(即终点)。在此过程中每走到一个节点,就会判断一次它是否为终点。

广度优先搜索会根据离起点的距离,按照从近到远的顺序对各节点进行搜索。而深度优先搜索会沿着一条路径不断往下搜索直到不能再继续为止,然后再折返,开始搜索下一条路径。

在广度优先搜索中,有一个保存候补节点的队列,队列的性质就是先进先出,即先进入该队列的候补节点就先进行搜索。
广度优先搜索:将点存储到队列中
广度优先遍历(Breadth_First_Search),又称为广度优先搜索,简称BFS。
深度遍历类似树的前序遍历,广度优先遍历类似于树的层序遍历。

邻接矩阵的广度遍历算法:

void BFSTraverse(Graph g)
{int i, j;Queue q;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;}InitQueue(&q);for(i = 0; i < g.numVertexes; i++)//对每个顶点做循环{if(!visited[i])               //若是未访问过{visited[i] = TRUE;printf("%c ", g.vexs[i]); //打印结点,也可以其他操作EnQueue(&q, i);           //将此结点入队列while(!QueueEmpty(q))     //将队中元素出队列,赋值给{int m;DeQueue(&q, &m);        for(j = 0; j < g.numVertexes; j++){//判断其他顶点若与当前顶点存在边且未访问过if(g.arc[m][j] == 1 && !visited[j]){visited[j] = TRUE;printf("%c ", g.vexs[j]);EnQueue(&q, j);}}}}}
}

邻接表的广度优先遍历:

void BFSTraverse(GraphList g)
{int i;EdgeNode *p;Queue q;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;}InitQueue(&q);for(i = 0; i < g.numVertexes; i++){if(!visited[i]){visited[i] = TRUE;printf("%c ", g.adjList[i].data);   //打印顶点,也可以其他操作EnQueue(&q, i);while(!QueueEmpty(q)){int m;DeQueue(&q, &m);p = g.adjList[m].firstedge;     找到当前顶点边表链表头指针while(p){if(!visited[p->adjvex]){visited[p->adjvex] = TRUE;printf("%c ", g.adjList[p->adjvex].data);EnQueue(&q, p->adjvex);}p = p->next;}}}}
}

对比图的深度优先遍历与广度优先遍历算法,会发现,它们在时间复杂度上是一样的,不同之处仅仅在于对顶点的访问顺序不同。可见两者在全图遍历上是没有优劣之分的,只是不同的情况选择不同的算法。

生成树

生成树的性质
一个有n个顶点的连通图的生成树有且仅有n-1条边
一个连通图的生成树并不唯一

图(Graph)的学习相关推荐

  1. 从图(Graph)到图卷积(Graph Convolution):漫谈图 神经⽹络模型 (⼀)

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者最近看了一些图与图卷积神经网络的论文,深感其强大,但一些Sur ...

  2. 数据结构--图(Graph)详解(四)

    数据结构–图(Graph)详解(四) 文章目录 数据结构--图(Graph)详解(四) 一.图中几个NB的算法 1.普里姆算法(Prim算法)求最小生成树 2.克鲁斯卡尔算法(Kruskal算法)求最 ...

  3. 数据结构--图(Graph)详解(三)

    数据结构–图(Graph)详解(三) 文章目录 数据结构--图(Graph)详解(三) 一.深度优先生成树和广度优先生成树 1.铺垫 2.非连通图的生成森林 3.深度优先生成森林 4.广度优先生成森林 ...

  4. 数据结构--图(Graph)详解(二)

    数据结构–图(Graph)详解(二) 文章目录 数据结构--图(Graph)详解(二) 一.图的存储结构 1.图的顺序存储法 2.图的邻接表存储法 3.图的十字链表存储法 4.图的邻接多重表存储法 二 ...

  5. 数据结构--图(Graph)详解(一)

    数据结构–图(Graph)详解(一) 文章目录 数据结构--图(Graph)详解(一) 一.图的基本概念 1.图的分类 2.弧头和弧尾 3.入度和出度 4.(V1,V2) 和 < V1,V2 & ...

  6. 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络 (二)

    在从图(Graph)到图卷积(Graph Convolution): 漫谈图神经网络 (一)中,我们简单介绍了基于循环图神经网络的两种重要模型,在本篇中,我们将着大量笔墨介绍图卷积神经网络中的卷积操作 ...

  7. 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (一)

    本文属于图神经网络的系列文章,文章目录如下: 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (一) 从图(Graph)到图卷积(Graph Convolutio ...

  8. 知识图谱-生物信息学-医学顶刊论文(Bioinformatics-2022)-SGCL-DTI:用于DTI预测的监督图协同对比学习

    14.(2022.5.21)Bioinformatics-SGCL-DTI:用于DTI预测的监督图协同对比学习 论文标题: Supervised graph co-contrastive learni ...

  9. 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (二)

    本文属于图神经网络的系列文章,文章目录如下: 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (一) 从图(Graph)到图卷积(Graph Convolutio ...

  10. 【图神经网络】图神经网络(GNN)学习笔记:基于GNN的图表示学习

    图神经网络GNN学习笔记:基于GNN的图表示学习 1. 图表示学习 2. 基于GNN的图表示学习 2.1 基于重构损失的GNN 2.2 基于对比损失的GNN 参考资料 本文主要就基于GNN的无监督图表 ...

最新文章

  1. 未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0
  2. neo4j查询多跳关系的方法
  3. 携程基于Quasar协程的NIO实践
  4. guava的正确引入方式_使用Guava的AbstractInvocationHandler正确完成代理
  5. 监督学习 | 集成学习 之Bagging、随机森林及Sklearn实现
  6. k8s学习(一)——kubectl与api-server之间的交互核心过程
  7. 智能识别云服务端平台之神【合合信息TextIn】
  8. 菜鸟驿站是什么快递_菜鸟驿站支持哪些快递(菜鸟驿站默认发什么快递)
  9. CAXA2007、2011,2013二次开发
  10. 从AWSome Day你可以学到什么?
  11. 本题要求编写程序,先将输入的一系列整数中的最小值与第一个数交换,然后将最大值与最后一个数交换,最后输出交换后的序列
  12. 高中数学基础-2.2.1 对数及对数的运算(下)
  13. 2019 年第 31 周 DApp 影响力排行榜 | TokenInsight
  14. Linux下四款Web服务器压力测试工具…
  15. mac安装win10后触摸板没有右键功能键的添加技巧
  16. 美年旅游_自由行_编辑自由行
  17. mysql on.000002_mysql | 同乐学堂
  18. Theano安装教程
  19. 从键盘输入圆柱体的半径和高,求圆柱体的表面积和体积
  20. 二元关系的关系性质判断

热门文章

  1. excel超级工具箱_这6个Excel高效办公插件,你都用过吗?
  2. jfinal html5,Jfinal框架整合webSocket技术功能实现
  3. php 动态 控件,PHP技术在动态网页表单控件提取中的应用研究
  4. kibana-7.15.2 中文简体
  5. 05_SpringCloud整合声明式HTTP客户端-Feign
  6. Linux6、7 系列 安装、卸载mysql
  7. 微信小程序---实现输入手机验证码功能
  8. Error和Exception(异常)
  9. matlab 求n 的和,MATLAB求1的阶乘加到n的阶乘和 不要现有的函数,要自己编写出来的...
  10. java加锁多线程改为单线程_GUI为什么不设计为多线程(用户事件和底层事件的流程是相反的,每层都加锁效率太低,共用一把锁那就是单线程)...