图
由顶点的有穷非空集合和顶点之间边的集合组成 G=(V,E)
线性表中,元素个数可以为零,称为空表
线性结构中,数据元素之间仅具有线性关系,元素之间的关系为前驱和后继
树中,结点个数可以为零,称为空树
树结构中,结点之间具有层次关系,结点之间的关系为双亲和孩子
图中,顶点个数不能为零,但可以没有边
图结构中,任意两个顶点之间都可能有关系,顶点之间的关系为邻接
邻接和依附
无向图中,对于任意两个顶点i和顶点j,若存在边(i,j),则称顶点i和顶点j互为邻接点,同时称边(i,j)依附于顶点i和顶点j
有向图中,对于任意两个顶点i和顶点j,若存在弧<i,j>,则称顶点i邻接到顶点j,顶点j邻接自顶点i,同时称弧<i,j>依附于顶点i和顶点j
有向图、无向图
若顶点vi和vj之间的边没有方向,则称这条边为无向边,表示为(vi,vj)
如果图的任意两个顶点之间的边都是无向边,则称该图为无向图
若从顶点vi到vj的边有方向,则称这条边为有向边,表示为<vi,vj>
如果图的任意两个顶点之间的边都是有向边,则称该图为有向图
简单图
不存在顶点到其自身的边,且同一条边不重复实现
无向完全图、有向完全图
如果任意两个顶点之间都存在边,则称该图为无向完全图
n个顶点的无向完全图有n×(n-1)/2条边
如果任意两个顶点之间都存在方向相反的两条弧,则称该图为有向完全图
n个顶点的有向完全图有n×(n-1)条边
相关知识
顶点的度:在无向图中,顶点v的度是指依附于该顶点的边数,通常记为TD (v)
顶点的入度:在有向图中,顶点v的入度是指以该顶点为弧头的弧的数目,记为ID (v)
顶点的出度:在有向图中,顶点v的出度是指以该顶点为弧尾的弧的数目,记为OD (v)
权:是指对边赋予的有意义的数值量
网:边上带权的图,也称网图
回路(环):第一个顶点和最后一个顶点相同的路径
简单路径:序列中顶点不重复出现的路径
简单回路(简单环):除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路
最大子图为图本身
在具有n个顶点和e条边的无向图G中,各顶点的度之和与边数之和的关系?(握手定理)
有n个顶点和e条边的有向图G中,各顶点入度之和与出度之和的关系?与边数之和的关系?
连通图
无向图:如果从一个顶点vi到另一个顶点vj(i≠j)有路径,则称顶点vi和vj是连通的。如果图中任意两个顶点都是连通的,则称该图是连通图。
连通分量:非连通图的极大连通子图称为连通分量。
强连通图:在有向图中,对图中任意一对顶点vi和vj (i≠j),若从vi到vj和从vj到vi均有路径,则称该有向图是强连通图。
强连通分量:非强连通图的极大强连通子图。
生成树:n个顶点的连通图G的生成树是包含G中全部顶点的一个极小连通子图。
遍历
图的遍历是在从图中某一顶点出发,对图中所有顶点访问一次且仅访问一次
图的遍历要解决的关键问题
① 在图中,从编号小的顶点开始选取遍历的起始顶点
② 从某个起点始可能到达不了所有其它顶点,应多次调用从某顶点出发遍历图的算法
③ 因图中可能存在回路,某些顶点可能会被重复访问,附设访问标志数组visited[n]避免遍历因回 路陷入死循环
④ 在图中,一个顶点可以和其它多个顶点相连,当这样的顶点访问过后,利用深度优先遍历和广 度优先遍历选取下一个要访问的顶点
深度优先遍历(入栈出栈思想)
基本思想:
⑴ 访问顶点v
⑵ 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历
⑶ 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到
遍历顺序:V1 V2 V4 V5 V8 V3 V6 V7
广度优先遍历(出队入队方式)
基本思想:
⑴ 访问顶点v
⑵ 依次访问v的各个未被访问的邻接点v1, v2, …, vk
⑶ 分别从v1,v2,…,vk出发依次访问它们未被访问的邻接点,并使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问,直至图中所有与顶点v有路径相通的顶点都被访问到
遍历顺序:V1 V2 V3 V4 V5 V6 V7 V8
图的特点:顶点之间的关系是m:n,即任何两个顶点之间都可能存在关系(边),无法通过存储位置表示这种任意的逻辑关系,所以,图无法采用顺序存储结构。
存储结构及实现
邻接矩阵(数组表示法)
基本思想:用一个一维数组存储图中顶点的信息,用一个二维数组(称为邻接矩阵)存储图中各顶点之间的邻接关系
假设图G=(V,E)有n个顶点,则邻接矩阵是一个n×n的方阵,定义为:
无向图
无向图的邻接矩阵的特点:主对角线为 0 且一定是对称矩阵
顶点i的度:邻接矩阵的第i行(或第i列)非零元素的个数
判断顶点 i 和 j 之间是否存在边:测试邻接矩阵中相应位置的元素arc[i][j]是否为1
求顶点 i 的所有邻接点:将数组中第 i 行元素扫描一遍,若arc[i][j]为1,则顶点 j 为顶点 i 的邻接点
求顶点 i 的出度:邻接矩阵的第 i 行元素之和
求顶点 i 的入度:邻接矩阵的第 i 列元素之和
有向图的邻接矩阵不一定对称,如有向完全图
网图
网图的邻接矩阵定义:
邻接表
基本思想:对于图的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表(对于有向图则称为出边表),所有边表的头指针和存储顶点信息的一维数组构成了顶点表
vertex:数据域,存放顶点信息
firstedge:指针域,指向边表中第一个结点
adjvex:邻接点域,边的终点在顶点表中的下标
next:指针域,指向边表中的下一个结点
无向图
每个结点对应图中的一条边,邻接表的空间复杂度为O(n+e)
顶点 i 的度为顶点a的边表中结点的个数
顶点 i 的出度为顶点 i 的出边表中结点的个数
顶点 i 的入度为各顶点的出边表中以顶点 i 为终点的结点个数
判断顶点 i 和顶点 j之间是否存在边:测试顶点 i 的边表中是否存在终点为 j 的结点
顶点 i 的所有邻接点:遍历顶点 i 的边表,该边表中的所有终点都是顶点 i 的邻接点
网图
图的存储结构的比较——邻接矩阵和邻接表
十字链表
结点结构
vertex: 数据域,存放顶点信息
firstin: 入边表头指针
firstout: 出边表头指针
tailvex: 弧的起点在顶点表中的下标
headvex:弧的终点在顶点表中的下标
headlink:入边表指针域;指向终点相同的下一条边
taillink: 出边表指针域;指向起点相同的下一条边
邻接多重表
vertex : 数据域,存储顶点数据
firstedage: 边表头指针,指向依附于该顶点的第一条边的边表结点
ivex ,jvex :与某条边依附的两个顶点在顶点表中的下标
ilink:指针域,指向依附于顶点ivex的下一条边
jlink:指针域,指向依附于顶点jvex的下一条边
方法比较
图的连通性
要想判定一个无向图是否为连通图,或有几个连通分量,通过对无向图遍历即可得到结果
连通图:仅需从图中任一顶点出发,进行深度优先搜索(或广度优先搜索),便可访问到图中所有顶点
非连通图:需从多个顶点出发进行搜索,而每一次从一个新的起始点出发进行搜索过程中得到的顶点访问序列恰为其各个连通分量中的顶点集
生成树
由深度优先遍历得到的为深度优先生成树,由广度优先遍历得到的为广度优先生成树
一个连通图的生成树可能不唯一,由不同的遍历次序、从不同顶点出发进行遍历都会得到不同的生成树
对于非连通图,通过图的遍历,将得到的是生成森林
最小生成树
生成树的代价:设G=(V,E)是一个无向连通网,生成树上各边的权值之和称为该生成树的代价
最小生成树:在图G所有生成树中,代价最小的生成树称为最小生成树
1.MST性质
假设G=(V, E)是一个无向连通网,U是顶点集V的一个非空子集,若(u, v)是一条具有最小权值的边,其中u∈U,v∈V-U,则必存在一棵包含边(u, v)的最小生成树
2.普里姆(Prim)算法
设G=(V, E)是一个无向连通网,T=(U, TE)是G的最小生成树, T的初始状态为U={u0}(u0∈V),TE={ },重复执行下述操作:在所有u∈U,v∈V-U的边中找一条代价最小的边(u, v)并入集合TE,同时v并入U,直至U=V
关键:是如何找到连接U和V-U的最短边
例:
3.克鲁斯卡尔(Kruskal)算法
设无向连通网为G=(V, E),令G的最小生成树为T=(U, TE),其初态为U=V,TE={ },然后,按照边的权值由小到大的顺序,考察G的边集E中的各条边
例:
最短路径
非网图:最短路径是指两顶点之间经历的边数最少的路径
网图:最短路径是指两顶点之间经历的边上权值之和最短的路径
1.Dijkstra算法
设集合S 存放已找到最短路径的顶点,S的初态只包含源点v,对vi∈V-S,假设从源点v到vi的有向边为最短路径。以后每求得一条最短路径v, …, vk,就将vk 加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径,重复上述过程,直到集合V中全部顶点加入到集合S中
例:
给定带权有向图G=(V, E),对任意顶点vi,vj∈V(i≠j),求顶点vi到顶点vj的最短路径:
法1:每次以一个顶点为源点,调用Dijkstra算法n次。显然,时间复杂度为O()
法2:弗洛伊德提出的求每一对顶点之间的最短路径算法—Floyd算法,其时间复杂度也是O()
2.Floyd算法
对于从vi到vj的弧,进行n次试探:首先考虑路径vi,v0,vj是否存在,如果存在,则比较vi,vj和vi,v0,vj的路径长度,取较短者为从vi到vj的中间顶点的序号不大于0的最短路径。在路径上再增加一个顶点v1,依此类推,在经过n次比较后,最后求得的必是从顶点vi到顶点vj的最短路径
例:
数组 dist为图的邻接矩阵 数组 path为两个顶点的连接
void Floyd(MGraph G)
{
for (i=0; i<G.vertexNum; i++)
for (j=0; j<G.vertexNum; j++)
{
dist[i][j]=G.arc[i][j];
if (dist[i][j]!=∞)
path[i][j]=G.vertex[i]+G.vertex[j];
else path[i][j]="";
}
for (k=0; k<G.vertexNum; k++)
for (i=0; i<G.vertexNum; i++)
for (j=0; j<G.vertexNum; j++)
if (dist[i][k]+dist[k][j]<dist[i][j]) {
dist[i][j]=dist[i][k]+dist[k][j];
path[i][j]=path[i][k]+path[k][j];
}
}
AOV网与拓扑排序
AOV(Activity On Vertex network )网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,称这样的有向图为顶点表示活动的网,简称AOV网
AOV网特点:AOV网中的弧表示活动之间存在的某种制约关系,AOV网中不能出现回路
拓扑序列:设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1, v2, …, vn称为一个拓扑序列,当且仅当满足下列条件:若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在顶点vj之前
拓扑排序:对一个有向图构造拓扑序列的过程称为拓扑排序
基本思想:从AOV网中选择一个没有前驱的顶点并且输出;从AOV网中删去该顶点,并且删去所有以该顶点为尾的弧;重复上述两步,直到全部顶点都被输出,或AOV网中不存在没有前驱的顶点
拓扑序列使得AOV网中所有应存在的前驱和后继关系都能得到满足
图的存储结构:采用邻接表存储 ,在顶点表中增加一个入度域
例:
AOE网与关键路径
AOE网 (Activity On Edge network ):在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,边上的权值表示活动的持续时间,称这样的有向图叫做边表示活动的网,简称AOE网
AOE网中没有入边的顶点称为始点(源点),没有出边的顶点称为终点(汇点)
AOE网性质:
⑴ 只有在某顶点所代表的事件发生后,从该顶点出发的各活动才能开始
⑵ 只有在进入某顶点的各活动都结束,该顶点所代表的事件才能发生
关键路径:在AOE网中,从始点到终点具有最大路径长度(该路径上的各个活动所持续的时间之和)的路径称为关键路径。
关键活动:关键路径上的活动称为关键活动
关键路径:开始时间余量为0的活动称为关键活动,由关键活动所形成的从源点到汇点的每一条路径
与关键活动有关的量:
⑴ 事件的最早发生时间ve[k]
ve[k]是指从始点开始到顶点vk的最大路径长度。这个长度决定了所有从顶点vk发出的活动能够开工的最早时间
⑵ 事件的最迟发生时间vl[k]
vl[k]是指在不推迟整个工期的前提下,事件vk允许的最晚发生时间
⑶ 活动的最早开始时间e[i]
若活动ai是由弧<vk , vj>表示,则活动ai的最早开始时间应等于事件vk的最早发生时间。因此,有:e[i]=ve[k]
⑷ 活动的最晚开始时间l[i]
活动ai的最晚开始时间是指,在不推迟整个工期的前提下, ai必须开始的最晚时间,若ai由弧<vk,vj>表示,则ai的最晚开始时间要保证事件vj的最迟发生时间不拖后,因此有:l[i]=vl[j]-len<,
>
计算各个活动的时间余量 l[k] - e[k],时间余量为0者即为关键活动