补充知识:
概括
一、深度优先遍历和广度优先遍历
- 深度优先遍历
- 广度优先遍历
二、图应用
- 最小生成树
1.1 Prim 算法
1.2 kruskal 算法 - 最短路径
2.1 单源最短路径——Dijkstra 算法
2.2 多源最短路径——Floyd 算法 - 关键路径
3.1 AOV网
3.2 拓扑排序
3.3 AOE网
3.4 关键路径
一、深度优先遍历和广度优先遍历
由于图结构本身的复杂性,所以图的遍历操作也较复杂,
主要表现在以下四个方面:
- 在图结构中,没有一个“自然”的首结点。图中任意一个顶点都可以作为第一个被访问的结点。
- 在非连通图中,从一个顶点出发,只能够访问它所在的连通分量上的顶点。因此,还需要考虑如何选取下一个出发点以访问图中其余的连通分量。
- 图中可能存在回路,且图的任一顶点都可能与其它顶点相通,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。
- 在图结构中,一个顶点可以和其它多个顶点相连,当这样的顶点访问过后,存在如何选取下一个要访问的顶点的问题
1.1 深度优先遍历
深度优先搜索遍历(Depth FisrstSearch),类似于树的先根遍历,是树的先根遍历的推广。
基本思想
- 访问顶点v;
- 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
- 重复上两步,直至图中所有和v有路径相通的顶点都被访问到。若此时图中尚有顶点未被访问,则另选一个图中未曾被访问的顶点作始点,重复上面的过程,直至图中所有的顶点都被访问。
例:
遍历序列:V1、V2、V4、V5、V8、V3、V6、V7
1.2 广度优先遍历
广度优先搜索遍历(Breadth First Search),类似于树的按层次遍历的过程。
基本思想:
- 访问顶点V
- 依次访问V未被访问的各个邻接点V1、V2……Vk
- 分别从V1,V2,…,vk出发依次访问它们未被访问的邻接点,并使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问。直至图中所有与顶点v有路径相通的顶点都被访问到。
若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作始点,重复上面的过程,直到图中的所有定点都被访问。
例:
遍历序列:V1、V2、V3、V4、V5、V6、V7、V8
注意:无论采用广度优先遍历还是深度优先遍历,如果选定的出发点不同或者遍历的图采用了不同的存储结构,则可能得到不同的遍历结果。只有当选取的出发点、采用的存储结构、遍历图的方式都确定的情况下,遍历的结果才是惟一的。
图的深度优先遍历类似于树的先序遍历,它所用到的数据结构是栈;图的广度优先遍历类似于树的层序遍历,它所用到的数据结构是队列。
二、图应用
2.1 最小生成树
- 最小生成树定义:
- 生成树的代价:设G = (V,E) 是一个无向连通网,生成树上各边的权值之和称为该生成树的代价。
- 最小生成树:在图G所有生成树中,代价最小的生成树称为最小生成树。
注意:最小生成树一定有n-1条边,但有n-1条边的生成树不一定是最小生成树。且最小生成树可能不唯一。
Prim 算法
伪代码:
- 初始化:U = {V0};TE{};
- 重复一下操作直到U = V
- 在E中寻找最短边(u,v),且满足u属于U,v属于V-U
- U = U+{V}
- TE = TE+{(u,v)}
例:
克鲁斯卡尔 kruskal 算法
Kruskal算法就是一种按照网中边的权值递增的顺序构造最小生成树的方法。
基本思想:设无向连通网为G = (V,E),令G的最小生成树为T = (U,TE),其 初态为:U = V,TE = {};然后,按照边的权值由小到大的顺序,考察G的边集E中的各个边。若被考察的边的两个顶点属于T的两个不同的连通分量,则将此边作为最小生成树的边加入到T中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T中的连通分量个数为1时,此连通分量便为G的一棵最小生成树。
Kruskal算法的基本思想用伪代码描述如下:
- 初始化:U = V;TE = {};
- 重复下述操作直到T中的连通分量个数为1:
- 再E中寻找最短边(u,v);
- 如果顶点u,v位于T的两个不同连通分量,则:
- 将边(u,v)并入TE;
- 将两个连通分量连成一个。
- 标记边(u,v),使得(u,v)不参加后续最短边的选取。
例: