图的基本知识点
一、基本概念
1.定义
图G由 顶点集V 和 边集E 组成,记为G = (V,E),其中,V(G)表示图G中顶点的有限非空集,E(G)表示图G中顶点之间的关系(边)的集合。若,V={v1,v2,…,vn},则用 |v| 表示图G中顶点的个数,也称,图G的阶;E = {(u,v)|u∈V,v∈V},用|E|表示图G中边的条数。
注意:
线性表可以是空表,树可以是空树,但图不可以是空图;即,图中不能一个顶点也没有,图中的顶点集V一定非空,但边集E可以为空,此时,图中只有顶点没有边。
<1>有向图
若E是有向边(弧)的有限集合,则G为有向图,弧是顶点的有序对,记为<v,w>,v为弧尾,w为弧头,称<v,w>为从顶点v到顶点w的弧;或v邻接w,w邻接自v。
<2>无向图
若E是无向边(弧)的有限集合,则G为无向图,弧是顶点的无序对,记为(v,w)=(w,v),称顶点v和顶点w互为邻接点,称边(v,w)依附于顶点v,w;或(v,w)和顶点v,w相关联。
<3>简单图(数据结构中一般只讨论简单图)
一个图G若满足:
a.不存在重复边;
b.不存在顶点到自身的边
则称G为简单图。
<4>多重图
若图G中某两个结点之间的边数多于一条,又允许顶点通过同一条边与自己关联,则图G为多重图。
<5>完全图(亦称,简单完全图)
a.有向完全图
有向图中,若任意两个顶点之间存在方向相反的两条弧,则称改图为有向完全图;
含有n个顶点的有向完全图有n(n-1)条有向边。
b.无向完全图
无向图中,任意两个顶点之间存在无向边,则称改图为无向完全图。
含有n个顶点的无向完全图有n(n-1)/2条边。
<6>子图
假设有两个图G=(V,E),G‘ = (V’ ,E‘),而且,V’是V的子集,E’是E的子集,则G’是G的子图;
若V(G‘) = V(G)的子图G’,则将其成为G的生成子图。
<7>连通,连通图及其连通分量
在无向图中,若从顶点v到顶点w有路存在,则v和w是连通的;
若图G中,任意两个的顶点都是连通的,则称G为连通图,否则为非连通图;
无向图中的极大连通子图为连通分量。
若一个图含有n个结点,并且边数小于n-1,则此图是非连通图。
<8>强连通图、强连通分量
强连通:
在有向图中,若从顶点v到w和从顶点w到顶点v之间都存在路径,则称这两个顶点之间是强连通的;
若图中任意两个顶点之间都是强连通的,则称之为强连通图,有向图中的极大强连通子图称为有向图的强连通分量。
<9>生成树、生成森林
连通图的生成树:
包含图中全部顶点的一个极小连通子图;
在非连通图中,连通分量的生成树构成了非连通图的的生成森林。
<10>顶点的度、入度和出度
a、顶点的度:以该顶点为一个端点的边的数目,记为TD(v);
b、入度:有向图中,以顶点v为终点的有向边数目,即为ID(v);
c、出度:有向图中,以顶点v为起点的有向边数目,即为OD(v),有向图顶点v的度等于入度和出度之和:TD(v)=ID(v)+OD(v)。
<11>边的权和网
在一个图中,每条边上的数值,称为该边的权值,这种带有权值的图称为带权图,也称网。
<12>稠密图、稀疏图(边数很少的图)
一般来说,图G满足|E|<|V|log|V|,则将之视为稀疏图,反之稠密图。
<13>路径、路径长度和回路
顶点vp与顶点vq之间的一条路径是指,顶点序列:vp,v1,v2...vn.vq;
路径上,边的数目称为路径长度;
第一个顶点与最后一个顶点相同的路径,称为回路或者环。
若一个图含有n个结点,并且具有大于n-1条边,则一定含有环。
<14>简单路径、简单回路
在路径序列中,定点不重复出现的路径,称为简单路径;
除了第一个和最后一个顶点外,其他顶点不会重复出现的回路,称简单回路。
<15>距离
从顶点u到顶点v的最短路径若是存在,则此路径的长度称为从u到v的距离;
若两个顶点之间不存在路径,则该距离记为无穷(∞)。
<16>有向树
一个顶点的入度为0、其余顶点的入度均为1的有向图,称有向树。
二、图的存储及其基本操作
1.邻接矩阵法
邻接矩阵储存,指的是用一个一维数组存储图中顶点的信息,用一个二维数组存储图中边的信息,存储顶点之间邻接关系的二维数组称为邻接矩阵。
结点数为n的图G=(V,E)的邻接矩阵是n*n的,将G的顶点编号为v1,v2,…vn。若(vi,vj)∈E,则A[i][j]=1,否则A[i][j]=0;
A[i][j] = 1,若组合(vi,vj)或者<vi,vj>是在E(G)中的边;A[i][j] = 0,若(vi,vj)或<vi,vj>不是在E(G)中的边。
图的邻接矩阵存储结构的定义如下:
#define MaxVertexNum 100 //定义图中存在的最大顶点数目
typedef char VertexType; //顶点的数据类型
typedef int ElemType; //带权图中边上权值的数据类型
typedef struct{
VertexType Vex[MaxVertexNum]; //顶点表
ElemType Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵,边表
int vexnum,arcnum; //图当前的顶点数和弧数
}MGraph;
注:
a.若是简单应用,我们可以直接使用二维数组来表示图的邻接矩阵;
b.当邻接矩阵中元素只用来表示相应的边是否存在时,我们可以用0,1来定义上面的ElemType;
c.无向图的邻接矩阵便是对称矩阵,对于规模特别大的邻接矩阵可采用,压缩存储;
d.邻接矩阵表示法的空间复杂度时O(n^2),其中,n为图的定点数|V|。
图的邻接矩阵表示法具有如下的特点:
a.无向图的邻接矩阵是一个对称矩阵,因此,实际存储时我们只需要存储上(或)下三角矩阵的元素;
b.对于无向图,邻接矩阵第i行(或第i列)的非零元素(或非无穷元素)个数正好是第i个顶点的度TD(vi);
c.对于有向图,邻接矩阵第i行(或第i列)的非零元素(或非无穷元素)个数正好是第i个顶点的度出度OD(vi),或入度ID(vi);
d.采用邻接矩阵储存法,很容易确定两个顶点之间是否有边相连,但是,要确定图中含有多少条边,则必须按行、列对每个元素进行检查,因此,需要花费的代价很大;
e.稠密图,适合用邻接矩阵的存储表示;
f.假设图G的邻接矩阵为A,A^n的元素 A^n[i][j]等于由顶点i到顶点j的长度为n的路径的数目。
2.邻接表法
当图为稀疏图的时候,采用邻接矩阵法,会浪费大量的存储空间,而图的邻接表法结合了顺序存储和链式存储的方法,大大减少了不必要的浪费;
邻接表,指的是对于图G中,每个顶点建立一个单链表,对于第i个单链表的结点表示依附于顶点vi的边(对于有向图则是,以顶点vi为尾的弧),这个单链表就称为顶点vi的边表(对于有向图则是出边表)。
边表的头指针和顶点的数据信息采用顺序存储(称为,顶点表),所以会在邻接表中存在两种结点:
顶点表结点和边表结点。
顶点表:
顶点域 | 边表头指针 |
---|---|
data | firstarc |
边表:
邻接点域 | 指针域 |
---|---|
adjvex | nextarc |
顶点表结点,由顶点域(data)和指向第一条邻接边的指针(firstarc)构成,边表(邻接表)结点由邻接点域(adjvex)和指向下一条邻接边的指针域(nextarc)构成。
无向图和有向图的邻接表实例分别如下:
图的邻接表存储结构定义如下:
#define MaxVertexNum 100 //定义图中顶点数目的最大值
typedef struct ArcNode{
//边表的结点
int adjvex; //该弧所指向的顶点的位置
struct ArcNode *next; //指向下一条弧的指针
加粗样式//InfoType info; //网的边权值
}ArcNode;
typedef struct VNode{
//顶点表的结点
VertexType data; //顶点信息
ArcNode *first; //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MaxVertexNum];
typedef struct{
AdjList vertices; //邻接表
int vexnum,arcnum; //图的顶点数和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
图的邻接表存储方法具有以下特点:
a.若G是无向图,则所需的存储空间为O|V| + 2|E|),2是因为,在无向图中,每条边在邻接表中出现了两次,若G是有向图,则所需的空间为O(|V| + |E|);
b.稀疏图,使用邻接表法可极大地节省存储空间;
c.在邻接表中,给定一个顶点,很容易找到其所有的临边,因为它只需要读取邻接表即可;
而若是在邻接矩阵中,相同的操作则需要扫描一行,花费时间为O(n);
若是想