图
G=(V,E)
- V:顶点(数据元素)的有穷非空集合;
- 边的有穷集合
- 无向图:每条边都是无方向的
- 有向图:每条边都是有方向的
- 完全图:任意两个点都有一条边相连
- 无向完全图:n个顶点,n(n-1)/2条边
- 有向完全图:n个顶点,n(n-1)条边
- 稀疏图:有很少边或弧的图(e<nlogn)
- 网:边/弧带权的图
- 邻接:有边/弧相连的两个顶点之间的关系
- 关联(依附):边/弧与顶点之间的关系
- 简单路径:除路径起点和终点可以相同外,其余顶点均不相同的路径
- 简单回路(简单环)除路径起点和终点相同外,其余顶点均不相同的路径
- 连通图(强连通图):在无(有)向图G=(V,{E})中,若对任何两个顶点v,u都存在从v到u的路径,则称G是连通图(强连通图)
- 有向图G的极大强连通子图称为G的强连通分量。该子图是G的强连通子图,将D的任何不在该子图中的顶点加入,子图不在是强连通的。
- 极小连通子图:该子图是G的连通子图,在该子图中删除任何一个边,子图不再连通。
- 生成树:包含无向图G所有顶点的极小连通子图。
图的存储结构
图的逻辑结构:多对多
- 无顺序存储结构:数组表示法(邻接矩阵)
- 链式存储结构:多重链表:①邻接表;②邻接多重表;③十字链表
邻接矩阵,多用于稠密图
- 无向图的邻接矩阵是对称的
- 完全图的邻接矩阵中,对角元素为0,其余为1
- 有向图的邻接矩阵可能是不对称的
- 顶点的出度:第i行元素之和
- 顶点的入度:第i行元素之和
- 顶点的度:第i行元素之和+第i列元素之和
邻接表,多用于稀疏图
- 顶点:按编号顺序将顶点数据存储在一维数组中
- 关联同一顶点的边(以顶点为尾的弧)
- 用线性链表存储
- 头结点:data firstarc
- 表结点:adjvex netarc(;链域:指示下一条边或弧)
- 若无向图中有N个顶点,e条边,则其邻接表需n个头结点和2e个表结点。适宜存储稀疏图,O(n+2e)
- 有向图的邻接表找出度易,找入度难
- 当邻接表的存储结构形成后,图便唯一确定
十字链表(有向图)
- 顶点结点:data,firstin第一条入弧;firstout第一条出弧
- 弧结点:tailvex弧尾位置;headvex弧头位置;hlink弧头相同的下一条弧;tlink弧尾相同的下一条弧
- 缺点:求结点的度困难
邻接多重表(无向图)
- 优点:容易求得顶点和边的信息
- 缺点:每条边都要存储两遍
图的遍历
深度优先搜索(DFS)
类似于树的先根遍历
算法6.5 采用邻接矩阵表示图的深度优先搜索遍历
//算法6.5 采用邻接矩阵表示图的深度优先搜索遍历
void DFS(AMGraph G, int v){
//图G为邻接矩阵类型
cout<<v; visited[v] = true; //访问第V个顶点
for(w = 0; w < G.vexnum; w++){
//依次检查邻接矩阵v所在的行
if((G.arcs[v][w] != 0) && (!visted[w])){
DFS(G, w);
//w是v的邻接点,如果w未访问,则递归调用DFS
}
}
}
邻接矩阵时间复杂度O(n^2)
邻接表时间复杂度O(n+e)
广度优先遍历
算法6.7 按广度优先非递归遍历连通图G
算法6.7 按广度优先非递归遍历连通图G
void BFS(Graph G, int v){
//按广度优先非递归遍历连通图G
cout<<v; visted[v] = true; //访问第v个顶点
InitQueue(Q); //辅助队列Q初始化,置空
EnQueue(Q, v); //v进队
while(!QueueEmpty(Q)){ //队列非空
DeQueue(Q, u); //队头元素出队并置为u
for(w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w))
if(!visited[w]){ //w为u尚未访问的邻接顶点
cout<<w; visited[w] = true;
EnQueue(Q, w); //w进队
}
}
}
生成树
所有顶点均由边连接在一起,但不存在回路的图
- 一个图可以有许多棵不同的生成树
- 生成树的顶点个数与图的顶点个数相同
- 生成树是图的极小连通子图,去掉一条边则非连通
- 一个有n个顶点的连通图的生成树有n-1条边
- 在生成树中再加一条边必然形成回路
- 生成树中任意两个顶点间的路径是唯一的
最小生成树:
给定一个无向网络,在该网的所有生成树中,使得各边权值之和最小的那棵生成树称为该网的最小生成树,也叫最小代价生成树
MST性质:在所有连通U中顶点和V-U中顶点的边中选取权值最小的边
普里姆(Prim)算法
从一个点出发依次按照最短路径找邻接顶点
- 算法思想:选择点
- 时间复杂度O(n^2), n为顶点数
- 适应范围 稠密图
克鲁斯卡尔(Kruskal)算法
依次从中选取代价最小的边,使其连通,不能形成环
- 算法思想:选择边
- 时间复杂度:O(eloge)(e为边数)
- 适应范围:稀疏图
最短路径
- 单源最短路径-用Dijkstra(迪杰斯特拉)算法
- 所有顶点间的最短路径-用Floyd(弗洛伊德)算法
有向无环图(DAG图):无环的有向图
AOV网:拓扑排序
- 有向图中,顶点表示活动,弧表示活动之间的优先制约关系,称这种有向图为顶点表示活动的网
- 在有向图中选一个没有前驱的顶点且输出之,
- 从图中删除该顶点和所有以它为尾的弧
- 重复上述两步,直至全部顶点均已输出或者不存在无前驱的顶点为止
AOE网:关键路径
- 有向图中,弧表示活动,以顶点表示活动的开始或结束事件,称这种有向图为边表示活动的网
- 关键路径是路径长度最长的路径
- 路径长度是路径是各活动持续时间之和
- ve(vj)-表示事件vj的最早发生时间
- vl(vj)-表示事件最迟发生的时间
- e(i)-表示活动ai最早开始的时间
- l(i)-表示活动ai的最迟开始的时间
- l(i)-e(i)-表示完成活动ai的时间余量
关键活动
- 关键路径上的活动,即l(i)==e(i),(即l(i)-e(i)==0)的活动
求解关键路径步骤
- 求ve(i)、vl(j)
- 求e(i)、l(i)
- 计算l(i)-e(i)