- 定义
图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V, E),G表示一个图,V是图G中顶点的集合,E是图G中边的集合。
注意:
a.线性表中把数据元素叫元素,树中叫结点,图中称之为顶点(Vertex);
b.线性表没有数据元素叫空表,树中没有结点叫空树,而图中不允许没有顶点,所以定义中才是顶点的有穷非空集合;
c.线性表中相邻数据元素之间具有线性关系,树中相邻两层结点具有层次关系,图中任意两个顶点之间都可能有关系(顶点之间的逻辑关系用边来表示,边集可以为空)。
- 图的分类
a.按有无方向
无向图(Undirected graphs):顶点+边(无向边Edge(vi, vj));
无向完全图:任意两个顶点都存在边,cntEdge = cntVex * (cntVex - 1) / 2。
有向图(Directed graphs):顶点+弧(有向边Arc<vi, vj>),弧有弧尾(vi)与弧头(vj)之分。
有向完全图:任意两个顶点都存在方向互为相反的两条弧,cntEdge = cntVex * (cntVex - 1)。
b.按边(弧)的多少
简单图*:不存在顶点到其自身的边,且同一条边不重复出现,下图为非简单图;
稀疏图/稠密图:就是相对于边(弧)的多少来说的。
c。其他分类
网:边(弧)带权值的图;
- 图的顶点与边的关系
a.无向图G=(V, {E}),如果边(v, v')∈E,则称顶点v与v'互为邻接点(Adjacent),即v和v'相邻接。边(v, v')依附于顶点v与v'(或者边(v, v')与顶点v与v'相关联);(注:个人觉得这就是废话,我这条边属于整个图所有边的集合,必然v和v'相邻啊,后面的必然也是废话。)
a.1.顶点v的度(Degree)是和v相关联的边的数目,记为TD(v);
b.有向图G=(V, {E}),如果弧<v, v'>∈E,则称顶点v邻接到顶点v',顶点v'邻接自顶点v。弧<v, v'>与顶点v和顶点v'相关联。
b.1.以顶点v为头的弧的数目称为v的入度(InDegree),记为ID(v);以顶点v为尾的弧的数目称为v的出度(OutDegree),记为OD(v)。
c.路径(Path):就简单的理解为一个顶点到另一个顶点走过的边(弧)的集合。
c.1.简单路径:序列中顶点不重复出现的路径;
c.2.环(回路):最后一个顶点和第一个顶点相同的路径;
c.2.1简单环(回路):就是除了最后一个顶点和第一个顶点重复以外,不存在其他顶点重复(左图简单环,右图非简单环)。
- 连通图相关
a.无向图中,顶点v到顶点v'存在路径,那么顶点v与顶点v'是连通的;
b.图中如果对于任意的顶点v与v‘都是连通的,且路径中的每条边都属于E(个人理解),那么该图是连通图。下图1为非连通图,图2为连通图。
c.连通分量:无向图中的极大连通子图;
注:1.要是子图;
2.子图要是连通的;
3.连通子图含有极大顶点数;
4.具有极大顶点数的连通子图包含依附于这些顶点的所有边。
上四图说明:图1是一个无向非连通图,但它有两个连通分量,图2和图3。而图4虽然是图1的子图,但它不满足连通子图的极大顶点数。
d.有向图类似与无向图,只是换了个名字。有向图的连通图叫强连通图,连通分量叫强连通分量。
e.生成树
e.1.无向图中连通且n个顶点n-1条边叫生成树;
e.2.有向图中一顶点入度为0其余顶点入度为1的是有向树;
e.3.一个有向图若干棵有向树构成森林。
- 图的存储结构
a.邻接矩阵
图的邻接矩阵(Adjacency Matrix)是用两个数组来表示图。顶点(一维数组),边或弧(二维数组(称邻接矩阵))。
对于无向图,邻接矩阵是个对称矩阵,某顶点的度=邻接矩阵中vi的第i行(或者列)所有元素之和。
对于有向图,邻接矩阵不是对称矩阵,顶点入度=邻接矩阵中vi的第i列之和,出度=第i行之和。
图的边上有了权值,也就是网图,邻接矩阵的定义如下:
注:因为权值只是一般来说才是正值,有时候也可能是0或者负值,所以使用无穷来表示一个不可能的值。
一个简单的有向网图及其存储结构如下图所示:
邻接绝阵存储结构代码实现
// 邻接矩阵方式存储图结构
typedef char VertexType; // 顶点的类型
typedef int EdgeType; // 边上的权值类型
#define MAXVEX 100 // 最大顶点数
#define INFINITY 65535 // 65535 代表 无穷
typedef struct
{
VertexType vexs[MAXVEX]; // 顶点表
EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,看作边表
int numVertexes, numEdges; // 图中当前的顶点数,边数
}MGraph;
|
创建无向网图代码实现
// 创建无向网图的邻接矩阵表示,n个顶点,e条边,时间复杂度O(n+n^2+e)
void CreateMGraph(MGraph *G)
{
int i, j, k, w;
//printf("请输入顶点数和边数:\n");
printf("input the number of vertex and edge(v, e):\n");
scanf("%d,%d", &G->numVertexes, &G->numEdges);
getchar();
for (i=0; i<G->numVertexes; i++) {
scanf("%c", &G->vexs[i]);
// printf("%c", G->vexs[i]);
}
for (i=0; i<G->numVertexes; i++) {
for (j=0; j<G->numVertexes; j++) {
G->arc[i][j] = INFINITY;
}
}
for (k=0; k<G->numEdges; k++) {
// printf("请输入边(vi, vj)上的下标i, 下标j和权值w:");
printf("input edge(vi, vj), index of i, j and the weight(w):");
scanf("%d,%d,%d", &i, &j, &w);
G->arc[i][j] = w;
G->arc[j][i] = G->arc[i][j]; // 图为无向图,矩阵对称
}
}
|
b.邻接表
邻接矩阵的问题:对于边数 相对 顶点数较少的图,该结构对存储空间的浪费较大。
邻接表(Adjacency List),数组与链表相结合的存储方法。一维数组(顶点,指向第一个邻接点的指针)),单链表(vi的所有邻接点)(无向图称为vi的边表,有向图称为vi作为弧尾的出边表)。
一个简单的无向图的邻接表结构如下图:
一个简单的有向图的邻接表与逆邻接表(方便顶点的入度+以顶点为弧头的弧)结构如下图:
对于带权值的网图,只需要在邻接表中间添加一个weight的数据域用来存放权值即可。如下图所示:
邻接表存储结构代码实现
// 邻接表方式存储图结构
typedef char VertexType;
typedef int EdgeType;
#define MAXVEX 100 // 最大顶点数
// 边表结点
typedef struct _EdgeNode
{
int adjvex; // 存储该顶点对应的下标
EdgeType weight;
struct EdgeNode *next;
}EdgeNode;
// 顶点表结点
typedef struct _VertexNode
{
VertexType data;
EdgeNode *firstedge; // 边表头指针
}VertexNode, AdjList[MAXVEX];
// 邻接表图结构
typedef struct
{
AdjList adjList;
int numVertexes, numEdges; // 当前顶点数和边数
}GraphAdjList;
|
创建无向图代码
// 无向图创建邻接表,时间复杂度O(n+e)
void createALGraph(GraphAdjList *G)
{
int i, j, k;
EdgeNode *e;
printf("Input the number of vertextes and edges:\n");
scanf("%d,%d", &G->numVertexes, &G->numEdges);
getchar();
for (i=0; i<G->numVertexes; i++) {
scanf("%c", &G->adjList[i].data);
G->adjList[i].firstedge = NULL;
}
for (k=0; k<G->numEdges; k++) { // 建立边表
printf("Input edge (vi, vj), i and j:\n");
scanf("%d,%d", &i, &j);
// 其实就是链表的头插法创建链表
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = j;
e->next = G->adjList[i].firstedge;
G->adjList[i].firstedge = e;
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = i;
e->next = G->adjList[j].firstedge;
G->adjList[i].firstedge = e;
}
}
|
c.十字链表、邻接多重表、边集数组等结构先不研究了 - 图的遍历
a.深度优先遍历
b.广度优先遍历 -
转载于:https://www.cnblogs.com/ifpelset/articles/4720057.html