图
1.定义
图(graph):图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中的顶点的集合,E是图G中边的集合。
注意:线性表可以是空表,树可以是空树,图不可以是空图,图可以没有边,但是至少要有一个顶点。
2.基本术语
顶点(Vertex):图中的数据元素。线性表中我们把数据元素叫元素,树中将数据元素叫结点。
边(Edge):顶点之间的逻辑关系用边来表示,边集可以是空的。
有向边(Directed Edge):若从顶点V1到V2的边有方向,则称这条边为有向边,也称弧(Arc)。起点是弧尾,终点是弧头。
无向边(Undirected Edge):若顶点V1到V2之间的边没有方向,则称这条边为无向边。
有向图(Directed graphs):图中任意两个顶点之间的边都是有向边。
无向图(Undirected graphs):图中任意两个顶点之间的边都是无向边。
完全图:任意两个点都有一条边相连。
稀疏图:有很少边或弧的图(e<nlogn),其中n是顶点的数目。
稠密图:有较多边或弧的图。
网:边/弧带权的图。
权:图中边或弧所有的相关数称为权。
邻接:
有边/弧相连的两个顶点之间的关系。
存在(,),则称和互为无向的邻接点。
存在<,>,则称和互为有向的邻接点,邻接到,邻接于。
关联(依附):边/弧与顶点之间的关系。
顶点的度:
与该顶点相关联的边的数目,记为TD(v)
在有向图中,顶点的度等于该顶点的入度与出度之和。
顶点v的入度是以v为终点的有向边的条数,记作ID(v)
顶点v的出度是以v为始点的有向边的条数,记作OD(v)
例:
路径:连续的边构成的顶点序列
路径长度:路径上边或弧的数目/权值之和。
回路(环):第一个顶点和最后一个顶点相同的路径。
简单路径:除路径起点和终点可以相同外,其余顶点均不相同的路径。
简单回路(简单环):除路径起点和终点相同外,其余顶点均不相同的路径。
连通图:在无向图G=(V,{E})中,若对任何两个顶点v,u都存在从v到u的路径,则称G是连通图。
强连通图:在有向图G=(V,{E})中,若对任何两个顶点v,u都存在从v到u的路径,则称G是强连通图。
连通分量:无向图G的极大连通子图称为G的连通分量。
(极大连通子图:该子图是G联通子图,将G的任何不在该子图中的顶点加入,子图不再联通)。
强连通分量:有向图G的极大连通子图称为G的强连通分量。
极小连通子图:该子图是G的连通子图,在该子图中删除任何一条边,子图不再联通。
子图:假设G=(V,{E})和G‘=(V’,{E’}),如果V’包含于V且E’包含于E,则称G’为G的子图。
生成树:包含无向图G所有顶点的极小连通子图。有n个顶点的连通图的生成树有n个顶点和n- 1条边。
有向树:有向图中一顶点入度为0其余顶点入度为1。
森林:一个有向图由若干棵有向树构成生成森林。
图的操作:建立,遍历,查找。
3.存储结构
图的逻辑结构:多对多(多个前驱,多个后继)
顺序存储结构:图没有顺序存储结构,但可以借助二维数组来表示元素之间的关系。即数组表示法(邻接矩阵)。
链式存储结构:多重链表有邻接表,邻接多重表以及十字链表
3.1邻接矩阵(数组)表示法
用两个数组,一个一维数组保存顶点集,一个二维数组表示邻接矩阵保存边集。
如果图G有n个顶点,则邻接矩阵为n*n二维数组,邻接矩阵的元素值为1或0(1表示两个顶点之间有边,0则表示没有)。
无向图的邻接矩阵表示法:
1.无向图的邻接矩阵是对称的。
2.顶点i的度=第i行(列)中1的个数。
3.完全图的邻接矩阵中,主对角线元素为0,其余1。
有向图的邻接矩阵表示法:
1.在有向图的邻接矩阵中:
第i行含义:以结点为尾的弧(即出度边)。
第i列含义:以结点为头的弧(即入度边)。
2.有向图的邻接矩阵可能是不对称的。
3.顶点i的出度=第i行元素之和
4.顶点i的入度=第i列元素之和
5.顶点i的度=第i行元素之和+第i列元素之和
网(既有权图)的邻接矩阵表示法:
定义:若两个顶点之间无边或弧,则相应元素用无穷大表示;其余元素值为边或弧上的权。
3.2邻接表表示法(链式)
使用数组表示顶点的集合,使用链表表示边的关系。
顶点:按编号顺序将顶点数据存储在一维数组中
边:关联同一顶点的边(以顶点为为尾的弧)用线性链表存储
单链表:有几个顶点就有几个单链表
头结点:顶点以及链域
| data | firstarc |
|---|
表结点:与顶点之间有边的顶点在一维数组的索引以及指针域。
| adjvex | nextarc |
|---|
如果有权重,可以在表结点再加一个域,存放权值。
无向图的邻接表表示法:
分析:
,,,,,五个顶点放在一维数组。
与顶点之间有边的顶点有,且,的索引分别为1,3,故后接两结点值域为3,1;另外,这两个结点的位置可以互换。
特点:
1.邻接表不唯一:邻结点的位置可以前后互换。
2.若无向图中有n个顶点、e条边,则其邻接表需要n个头结点和2e个表结点。适宜存储稀疏图。
3.空间复杂度:若无向图中有n个顶点、e条边,其空间复杂度:O(n+2e)
4.无向图中顶点的度为第i个单链表中的结点数
有向图的邻接表表示法:
顶点以出度为边的对应顶点为邻结点建立的邻接表称为邻接表。
指向,且,的索引分别为1,2,故后接两结点值域为2,1;另外,这两个结点的位置可以互换。
特点:
1.邻接表不唯一
2.若有向图中有n个顶点、e条边,则其邻接表需要n个头结点和e个表结点。
3.顶点的出度为第i个单链表中的结点个数。
4.顶点的入度为整个单链表中邻接点阈值是i-1的结点个数。
5.找出度容易,找入度难。
6.空间复杂度:若有向图中有n个顶点、e条边,其空间复杂度:O(n+e)
顶点以入度为边的对应顶点为邻结点建立的邻接表称为逆邻接表。
图G中指向且的索引为3,故后接结点值域为2,指针域为空。
特点:
1.邻接表不唯一
2.若有向图中有n个顶点、e条边,则其邻接表需要n个头结点和e个表结点。
3.顶点的入度为第i个单链表中的结点个数。
4.顶点的出度为整个单链表中邻接点阈值是i-1的结点个数。
5.找入度容易,找出度难。
6.空间复杂度:若有向图中有n个顶点、e条边,其空间复杂度:O(n+e)
所以建立有向图的邻接表,应根据所需结果相应的选择哪种邻接表。
网(既有权图)的邻接表表示法:
跟无向图的邻接表差不多,只不过表结点多一个权重域。
邻接表与邻接矩阵存储:
邻接表特点:
1.方便找任一顶点的所有”邻接点“
2.节约稀疏图的空间:
无向稀疏图需要N个头指针+2E个结点(每个结点至少两个域)
有向稀疏图需要N个头指针+E个结点(每个结点至少两个域)
3.对无向图方便计算顶点的度;对有向图:只能计算出度;需要构造"逆邻接表(存指向自己的边)"来方便计算入度。
4.不方便检查任意一对顶点间是否存在边。
3.3邻接矩阵与邻接表表示法的关系
1.联系:邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。
2.区别:
1)对于任一确定的无向图,邻接矩阵是唯一的(行列号与定点编号一致),但邻接表不唯一(链接次序与顶点编号无关)。
2)邻接矩阵的空间复杂度为O(),而邻接表的空间复杂度为O(n+e),其中n是顶点个数,e是边数。
3.用途:邻接矩阵多用于稠密图,邻接表多用于稀疏图。
3.4十字链表-用于有向图
十字链表是有向图的另一种链式存储结构。可以看成是将有向图的邻接表和逆邻接表结合起来的一种链表。
在十字链表中,每一条弧对应十字链表中的一个弧结点,同时有向图中的每一个顶点在十字链表中对应有一个结点,记作顶点结点。
起点是弧尾,终点是弧头。
firstin指向入度边,firstout指向出度边
在十字链表中,既容易找到以为尾的弧,也容易找到以为头的弧,因而容易求得顶点的出度和入度。
3.5邻接多重表-用于无向图
邻接多重表是无向图的另一种链式存储结构。
在邻接多重表中,每一条边用一个结点表示,它由如下所示的6个域组成。
4.遍历
定义:从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且使每一个顶点仅被访问一次,就叫做图的遍历,它是图的基本运算。
遍历实质:找每一个顶点的邻接点的过程。
图的特点:图中可能存在回路,且图的任一顶点都可能与其他顶点相同,在访问完某一个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。
避免重复访问:设置辅助数组visited[n],用来标记每一个被访问过的点。初始状态visited[i]=0,顶点i被访问,visited[i]值加一。
图常用的遍历:
- 深度优先搜索(Depth_First Search——DFS)
- 广度优先搜索(Breadth_First Search——BFS)
4.1深度优先遍历(DFS)
深度优先遍历顾名思义就是一条路走到黑,再寻其他未走过的路。其类似于树的先序遍历。
思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。显然,深度优先搜索是一个递归的过程。
方法:
- 在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w1
- 再从w1出发,访问与w1邻接但未被访问过的顶点w2
- 然后再从w2出发,进行类似的访问
- 如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止
- 接着,退回一步,退到前一次刚访问过的顶点,看是否还有其他没有被访问过的顶点
- 如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问
- 如果没有,就再退回一步进行搜索。重复上述过程,直至连通图中所有顶点都被访问过。
时间复杂度:
4.2广度优先遍历(BFS)
BFS类似于树的层次遍历。
方法:从图的某一顶点出发,首先依次访问该顶点的所有邻接顶点,再按照这些顶点被访问的先后顺序依次访问与它们相邻接的所有未被访问的顶点;重复此过程,直至所有顶点均被访问为止。
时间复杂度:
1.如果使用邻接矩阵存储,则BFS对于每一个被访问到的顶点,都要循环检测矩阵中的整整一行(n个元素),故时间复杂度为O()
2.如果使用邻接表存储,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,加上访问n个头结点的时间,时间复杂度为O()
4.3DFS与BFS算法比较
- 空间复杂度相同,都是O(n)(借用了堆栈或队列)
- 时间复杂度只与存储结构有关,而与搜索路径无关。