图的基本知识
知识点
图的概念
定义
图是由顶点的非空有穷集合(用V表示该集合)与顶点之间的关系(边或弧)的集合(用E表示该集合)构成的结构。
以形式化表示为G=(V,E)
其中,V为顶点的非空有穷集合,E为关系的有穷集合。
有关术语
顶点的度
所谓某个顶点V的度是指依附于该顶点的边或弧的数量,记为D(V)。无向图就是这样。
而对于有向图,要区分顶点的出度与入度的概念。出度记为OD(V),入度记为ID(V)。 D(V)=OD(V)+ID(V)。
结论
① 所有顶点的度之和等于边或弧的条数2倍。脑补:两个顶点一条边的情形。
② 具有n个顶点的无向图中边的数目最多为n(n-1)/2,脑补:三个顶点两条边的情形,三个顶点间,两两有条边相连也就是最多有3条边相连.也就是3*2/2
具有n个顶点的有向图中边(弧)的数目最多为n(n-1)。脑补两个顶点一条边,因为是有向图,所以两个顶点间有2条线
路径
两个顶点之间路径,出发点与终止点相同的路径称为环或回路。序列中顶点不重复出现的路径称为简单路径。
对于不带权的图,两个顶点之间的路径长度是指该路径上所经过的边的数目。
对于带权的图,两个顶点之间的路径长度是指该路径上所经过的边上的权值之和。
子图
边属于一个图,顶点也属于一个图。一个图最大的子图是其自身。
图连通
无向图连通
若图中任意两个顶点之间都有路径,就称该无向图是连通的。
有向图连通
若顶点Vx与Vy之间有路径,并且顶点Vy与Vx之间也有路径,就称Vx与Vy是连通的。记忆:有向图双向连通才是连通
若图中任意两个顶点之间都有连通,就称该有向图是强连通的。
连通分量
无向图中的极大连通子图称为最强连通分量。任何一个连通图的的连通分量只有一个,是它本身。非连通的无向图有多个连通分量。如下图所示:
强连通分量:有向图中的极大强连通子图。
① 强连通图只有一个强连通分量,即是其自身。
② 非强连通的有向图有多个强连分量,如下图所示:
图的存储结构
存储方法有邻接矩阵存储方法与邻接表存储方法。
邻接矩阵表示法
设G=(V,E)是具有n个顶点的图,则
特点
① 无向图的邻接矩阵一定是一个对称矩阵。因此,按照压缩存储的思想,在具体存放邻接矩阵时只需存放上(或者下)三角形阵的元素即可。
② 不带权的有向图的邻接矩阵一般来说是一个稀疏矩阵(特别是对于稀疏图),于是可以采用三元组表的方法存储邻接矩阵。
③ 对于无向图,邻接矩阵的第i行(或者第i列)非零元素(或者非∞元素)的个数正好是第i个顶点的度D(Vi)。
④ 对于有向图,邻接矩阵的第i行(或者第i列)非零元素(或者非∞元素)的个数正好是第i个顶点的出度OD(Vi)(或者入度ID(Vi))。
⑤ 对于无向图,邻接矩阵的所有非零元素(或者非∞元素)的个数正好是边数的2倍。
⑥ 对于有向图,邻接矩阵的所有非零元素(或者非∞元素)的个数正好等于弧数。
⑦ 一个图的邻接矩阵表示是唯一的。
邻接矩阵结构表示
#define MaxVertexNum 50 //最大顶点数
typedef Struct {
vertexTvpe vexs[MaxVertexNum]; //顶点数组,类型假定为char型
Adjmstrix arcs[MaxVertexNum][MaxVertexNum]; //邻接矩阵,假定为int型
}MGraph;
无向图邻接矩阵算法
#define MaxVertexNum 50 //最大顶点数
typedef Struct {
vertexTvpe vexs[MaxVertexNum]; //顶点数组,类型假定为char型
Adjmstrix arcs[MaxVertexNum][MaxVertexNum]; //邻接矩阵,假定为int型
} MGraph;
Void CreateMGraph(MGraph *G, int n, int e)
{ //采用邻接矩阵表示法构造无向网G,n、e表示图的当前顶点数和边数
int i, j, k, w;
scanf("%d,%d", &n, &e); //读入顶点数和边数
for (i = 0; i < n; i++) //输入顶点信息
scanf("%c", &G->vexs[i]);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) G->arcs[i][j] = INT_MAX; //初始化邻接矩阵元素为无穷大,一般填32767
for (k = 0; k < e; k++) //读入e条边,建立邻接矩阵
//读入一条边的两端顶点序号i、j及边上的权W
{
scanf("%d,%d,%d", &i, &j, &w);
G->arcs[i][j] = w;
G->arcs[j][i] = w; //置矩阵对称元素权值
}
}
邻接表表示
相关软考总结:数据结构与算法基础-图
对于具有n个顶点的图建立n个线性链表。每一个链表最前面都分别设置一个称之为顶点表结点,n个顶点构成一个数组结构。第i个链表中的每一个链结点称之为边表结点。
特点
① 一个图的邻接表表示法不唯一,这是因为邻接表中各结点的链接次序取决于建立邻接表的算法(前插法还是后插法建链表)及边的输入次序。
② 对于无向图,若它有n个顶点,e条边,则其邻接表中需要2e+n个结点。其中有2e个边表结点,n个顶点表结点。边表结点的个数一定是偶数,为边数的2倍。
③ 对于有向图,若它有n个顶点,e条边,则其邻接表中需要e+n个结点。其中有e个边表结点,n个顶点表结点。
④ 对于无向图,第i个链表中的边表结点的数目是第i个顶点的度。
⑤ 对于有向图,第i个链表中的边表结点的数目是第i个顶点的出度。在其逆邻接表中,第i个链表中的边表结点的数目是第i个顶点的入度。
邻接表结构定义
#define MaxVertexNum 20
typedef char VertexType;
typedef struct node //边表结点类型
{
int adjvexj //顶点的序号
struct node *next; //指向下一条边的指针
} EdgeNode;
typedef struct vnode //顶点表结点
{
VertexType vertex; //顶点域
EdgeNode *link; //边表头指针
} VNode,Adjlist[MaxVertexNum]; //邻接表
typedef Adjlist ALGraph; //定义为图类型
无向图邻接表算法
#define MaxVertexNum 20
typedef char VertexType;
typedef struct node //边表结点类型
{
int adjvexj //顶点的序号
struct node *next; //指向下一条边的指针
} EdgeNode;
typedef struct vnode //顶点表结点
{
VertexType vertex; //顶点域
EdgeNode *link; //边表头指针
} VNode, Adjlist[MaxVertexNum]; //邻接表
typedef Adjlist ALGraph; //定义为图类型
void CreateGraph(ALGraph GL, int n, int e) { // n为顶点数,e为图的边数
int i, j, k;
EdgeNode *p;
for (i = 0; i < n; i++) //建立顶点表
{
GL[i].vertex = getchar(); //读入顶点信息
GL[i].link = NULL; //边表头指针置空
}
for (k = 0; k < e; k++) //采用头插法建立每个顶点的邻接表
{
scanf("%d,%d", &i, &j); //读入边(vi,vj)的顶点序号
p = (EdgeNode *)malloc(sizeof(EdgeNode)); //生成新的边表结点
p->adjvex = j; //将邻接点序号j赋给新结点的邻接点域
p->next = GL[i].link;
GL[i].link = p; //将新结点插入到顶点vi的边表头部
p = (EdgeNode *)malloc(sizeof(EdgeNode)); //生成新的边表结点
p->adj.vex = i; //将邻接点序号i赋给新结点的邻接点域
p->next = GL[j].link;
GL[j].link = p; //将新结点插入到顶点vj的边表头部
}
}
); //生成新的边表结点
p->adj.vex = i; //将邻接点序号i赋给新结点的邻接点域
p->next = GL[j].link;
GL[j].link = p; //将新结点插入到顶点vj的边表头部
}
}