目录
定义和一些专业术语:
-
图用G表示
-
图的表示:Graph=(Vertex,Edge), 简写:G=(V,E); 分别是顶点和边。
-
图主要分为 有向图和无向图,有向图指的是图中的边有方向,而无向图没有。
-
弧:我们也把有向图的边称为弧。
-
完全图:任意两个节点之间都有一边相连。无向完全图是每两个顶点之间都有一个边相连,有向完全图是每连个顶点之间有两个指向不同方向的边。如果有n个节点,那么完全无向图有n*(n-1)/2条边,有向完全图有n*(n-1)条边。
-
稀疏图:有很少的边/弧,如果有n个顶点,那么当满足e<nlogn的时候属于稀疏图(log底数为2)。
-
稠密图:有较多的边/弧。
-
网:边/弧带权的图
-
邻接:有边/弧相连的两个顶点之间的关系。无向图中邻接点表示为(vi,vj),有向图中表示为<vi,vj>
-
依附:边/弧与顶点之间的关系。
-
顶点的度:与该顶点相关联的边的数目,记为TD。有向图中又具体分为入度 ID和出度 OD。
-
路径:连续的边构成的顶点序列。
-
路径长度:路径上边/弧的数目之和。
-
连通图(强连通图):任意两个顶点之间都存在路径。无向图称为连通图,有向图称为强连通图。
-
子图:设有G1和G2,G1的顶点包含所有G2的顶点,G1的边/弧包含所有G2的边/弧。
-
连通分量(强连通分量):即一个图的极大(强)连通子图,G2是G1的子图,且G2是连通图(强连通图),将G1中任一不属于G2的顶点加入G2,G2都不再连通。
-
极小连通子图:该子图是G的连通子图,但是该子图中删去任何一条边/弧都不再连通。
-
生成树:包含无向图G所有顶点的极小连通子图
-
生成森林:对于非连通图,由各个连通分量的生成树的集合。
拓展
-
AOE网:只有一个入度为0的顶点,称为开始顶点(源点);只有一个出度为0的点,称为结束顶点(汇点)。
-
关键路径:从源点到汇点有最大长度的路径叫做关键路径。
图的存储
一、利用邻接矩阵存储:
稠密图更适合使用邻接矩阵的方法进行存储,因为这样可以尽可能利用空间。这种表示分别由两个数组完成,一个一维数组用于存放顶点,一个二维数组用于存储边/弧。
-
无向图
-
定义一个一维数组存储顶点。
-
定义一个二维数组存储边/弧,数组下标表示对应的顶点下标,如果对应两个下标的顶点之间存在边,那么就把该位置赋值为1,不存在边就赋值为0。
-
因为无效图的边没有方向之分,所以在矩阵中对角线上方和下方是完全对称的,一般只存储一侧就可以了。
v0 v1 v2 v3
v0 0 1 1 1
v1 1 0 1 0
v2 1 1 0 1
v3 1 0 1 0
-
有向图
-
定义一个一维数组存储顶点。
-
定义一个二维数组E[i][j],如果从i有指向j的弧,则数组该位置赋值为1,否则赋值为0。
-
因为有向图中的弧是有方向的,所以必须表示一个完整的矩阵。
v0 v1 v2 v3
v0 0 0 1 1
v1 1 0 1 1
v2 1 0 0 1
v3 1 0 1 0
-
带权图
在有向图和无向图的基础上,如果边/弧带权,就把代表该边/弧的对应下标的二维数组赋值为权重。
v0 v1 v2 v3
v0 0 1 9 6
v1 1 0 1 0
v2 5 1 0 7
v3 1 0 3 0
//邻接矩阵代码描述
#define V_num 6
typedef char V //顶点数据类型
typedef int Eweight //边或弧的权重数据类型
typedef struct Graph{
V v[V_num]; //顶点
E e[V_num][V_num]; //边/弧
int vnum,enum; //当前顶点和边或弧的数量
}G,*PG;
二、利用邻接表存储
引入:
邻接矩阵适合存储稠密图,但是如果用邻接矩阵存储稀疏表就会浪费空间。这时候使用邻接表就显得更为合适。
概述:
邻接表结合力顺序表和链式存储方法,可以减少浪费不必要的空间。
-
无向图
-
顶点:由结构体一维数组构成,数组下标代表相应顶点的编号,内容有两个成员:数据域和第一个边节点的指针。
-
边节点(边表节点):由结构体构成:数据域存储父顶点(这个词我编的)的邻接顶点的编号,指针域存储父节点其他边节点的指针。
-
有向图
-
有向图的邻接表的地念中的指针只指向 出边节点,不包括入边节点。
-
其余均与无向表一致。
-
带权图
比不带权图的边节点中多了一个数据域用于存储权重。
//邻接表算法描述
#define V_num 6
typedef char V //顶点数据类型
typedef int Eweight //边或弧的权重数据类型
typedef struct E{ //边节点
int dad; //父顶点编号
Eweight weight; //该边的权重
struct E next; //父顶点另一边节点的指针
}E,*PE;
typedef struct V{ //顶点
V v; //数据域
PE first; //第一个边节点的指针
}v_array[V_num];
type struct Graph{
v_array v_list; //存储顶点的结构体数组
int E_num; //当前边的数量
}
三、十字链表
引入:
邻接表可以很大程度上节省空间,但缺陷是统计一个顶点的入度时必须遍历全部顶点。
概述:
十字链表是一种把邻接表和逆邻接表结合起来的链式存储结构,主要用于存储有向图。
组成
-
顶点:是一个有三个成员的结构体类型,分别是数据域、第一个入边节点指针、第一个出边节点指针。
-
边节点(边表节点):是一个有四个成员的结构体,分别是弧起点顶点的下标、弧终点顶点的下标、弧上一个边节点的指针、弧下一个边节点的指针。
四、邻接多重表
引入:
邻接表容易获取顶点和边的信息,但是当想要删除某一条边的时候,需要对两个顶点的编标都进行遍历删除,这样显得繁琐,而邻接多重链表可以很好地解决这个问题。
概述:
邻接多重链表是无向图的一种链式存储结构。
组成:
-
顶点:顶点结构体由两部分组成,数据域和第一个边节点。
-
边节点(边表节点):由四部分组成,两个依附的节点下标,、上一个边节点的指针、下一个边节点的指针。
本篇博客主要介绍了图的理论知识,在下一篇将会讲解图的遍历和一些基本操作用代码如何实现。